Heim  >  Artikel  >  Web-Frontend  >  Teilen Sie drei Methoden zur Implementierung der bidirektionalen Datenbindung in JavaScript mit

Teilen Sie drei Methoden zur Implementierung der bidirektionalen Datenbindung in JavaScript mit

黄舟
黄舟Original
2017-03-21 14:41:001874Durchsuche

In diesem Artikel wird hauptsächlich eine Zusammenfassung der drei Methoden von Javascript vorgestellt, um eine bidirektionale Datenbindung zu erreichen. Die Front-End-Ansichtsschicht und die Datenschicht müssen manchmal eine Zwei-Wege-Datenbindung implementieren. Derzeit gibt es drei Haupttypen der Zwei-Wege-Bindung. Interessierte können sich darüber informieren.

Zwei-Wege-Bindungsmethode für Front-End-Daten

Die Ansichtsschicht und die Datenschicht des Front-Ends müssen manchmal eine bidirektionale Bindung implementieren (Zwei-Wege-Bindung), zum Beispiel MVVM-Framework, datengesteuerte Ansicht, Ansichtszustandsmaschine usw., wir haben mehrere aktuelle gängige bidirektionale Datenbindungs-Frameworks untersucht und zusammengefasst. Derzeit gibt es drei Hauptmethoden zur Implementierung der bidirektionalen Datenbindung:

1. Manuelle Bindung

Die Hauptidee ist die Verwendung des Beobachter-Programmiermodus Definieren Sie Get- und Set-Methoden für das Datenobjekt (natürlich gibt es auch andere Methoden), rufen Sie beim Aufrufen manuell Get- oder Set-Daten auf und starten Sie den Rendervorgang der UI-Ebene, nachdem die Daten hauptsächlich geändert wurden Wird in Szenarien verwendet, in denen die Ansicht Datenänderungen steuert. Wenn sich die UI-Ebene ändert, werden Ereignisse wie Änderung, Tastendruck, Tastendruck und andere Ereignisse des Doms überwacht, um Ereignisse zur Änderung der Daten des Doms auszulösen Datenschicht. Der gesamte Prozess wird durch Funktionsaufrufe abgeschlossen.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>data-binding-method-set</title>
</head>
<body>
  <input q-value="value" type="text" id="input">
  <p q-text="value" id="el"></p>
  <script>
    var elems = [document.getElementById(&#39;el&#39;), document.getElementById(&#39;input&#39;)];

    var data = {
      value: &#39;hello!&#39;
    };

    var command = {
      text: function(str){
        this.innerHTML = str;
      },
      value: function(str){
        this.setAttribute(&#39;value&#39;, str);
      }
    };

    var scan = function(){    
      /**
       * 扫描带指令的节点属性
       */
      for(var i = 0, len = elems.length; i < len; i++){
        var elem = elems[i];
        elem.command = [];
        for(var j = 0, len1 = elem.attributes.length; j < len1; j++){
          var attr = elem.attributes[j];
          if(attr.nodeName.indexOf(&#39;q-&#39;) >= 0){
            /**
             * 调用属性指令,这里可以使用数据改变检测
             */
            command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]);
            elem.command.push(attr.nodeName.slice(2));
          }
        }
      }
    }

    /**
     * 设置数据后扫描
     */
    function mvSet(key, value){
      data[key] = value;
      scan();
    }
    /**
     * 数据绑定监听
     */
    elems[1].addEventListener(&#39;keyup&#39;, function(e){
      mvSet(&#39;value&#39;, e.target.value);
    }, false);

    scan();

    /**
     * 改变数据更新视图
     */
    setTimeout(function(){
      mvSet(&#39;value&#39;, &#39;fuck&#39;);
    },1000)

  </script>
</body>
</html>
2. Dirty-Checking-Mechanismus


Dargestellt durch das typische MVVM-Framework

AngularJS

, prüft Angular die Dirty-Daten, um sie betriebsbereit zu machen Aktualisierungen auf der UI-Ebene. Es gibt ein paar Dinge, die Sie über die Dirty-Erkennung von Angular wissen müssen: – Der Dirty-Erkennungsmechanismus verwendet keine geplante Erkennung. - Der Zeitpunkt der Dirty-Erkennung liegt dann, wenn sich die Daten ändern. - Angular kapselt häufig verwendete DOM-Ereignisse, XHR-Ereignisse usw. und löst den Digest-Prozess bei der Eingabe von Angular aus. – Im Digest-Prozess wird der Rootscope durchlaufen und alle Beobachter überprüft. (Für das spezifische Design von Angular können Sie sich andere Dokumente ansehen. Hier besprechen wir nur die Datenbindung.) Schauen wir uns dann an, wie die Dirty-Erkennung durchgeführt wird: Suchen Sie hauptsächlich alle mit den Daten verbundenen Elemente anhand der festgelegten Daten und vergleichen Sie sie dann mit den Daten Änderungen, wenn es sich ändert, führen Sie Befehlsoperationen aus

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>data-binding-drity-check</title>
</head>

<body>
  <input q-event="value" ng-bind="value" type="text" id="input">
  <p q-event="text" ng-bind="value" id="el"></p>
  <script>

  var elems = [document.getElementById(&#39;el&#39;), document.getElementById(&#39;input&#39;)];
  
  var data = {
    value: &#39;hello!&#39;
  };

  var command = {
    text: function(str) {
      this.innerHTML = str;
    },
    value: function(str) {
      this.setAttribute(&#39;value&#39;, str);
    }
  };

  var scan = function(elems) {
    /**
     * 扫描带指令的节点属性
     */
    for (var i = 0, len = elems.length; i < len; i++) {
      var elem = elems[i];
      elem.command = {};
      for (var j = 0, len1 = elem.attributes.length; j < len1; j++) {
        var attr = elem.attributes[j];
        if (attr.nodeName.indexOf(&#39;q-event&#39;) >= 0) {
          /**
           * 调用属性指令
           */
          var dataKey = elem.getAttribute(&#39;ng-bind&#39;) || undefined;
          /**
           * 进行数据初始化
           */
          command[attr.nodeValue].call(elem, data[dataKey]);
          elem.command[attr.nodeValue] = data[dataKey];
        }
      }
    }
  }

  /**
   * 脏循环检测
   * @param {[type]} elems [description]
   * @return {[type]}    [description]
   */
  var digest = function(elems) {
    /**
     * 扫描带指令的节点属性
     */
    for (var i = 0, len = elems.length; i < len; i++) {
      var elem = elems[i];
      for (var j = 0, len1 = elem.attributes.length; j < len1; j++) {
        var attr = elem.attributes[j];
        if (attr.nodeName.indexOf(&#39;q-event&#39;) >= 0) {
          /**
           * 调用属性指令
           */
          var dataKey = elem.getAttribute(&#39;ng-bind&#39;) || undefined;

          /**
           * 进行脏数据检测,如果数据改变,则重新执行指令,否则跳过
           */
          if(elem.command[attr.nodeValue] !== data[dataKey]){

            command[attr.nodeValue].call(elem, data[dataKey]);
            elem.command[attr.nodeValue] = data[dataKey];
          }
        }
      }
    }
  }

  /**
   * 初始化数据
   */
  scan(elems);

  /**
   * 可以理解为做数据劫持监听
   */
  function $digest(value){
    var list = document.querySelectorAll(&#39;[ng-bind=&#39;+ value + &#39;]&#39;);
    digest(list);
  }

  /**
   * 输入框数据绑定监听
   */
  if(document.addEventListener){
    elems[1].addEventListener(&#39;keyup&#39;, function(e) {
      data.value = e.target.value;
      $digest(e.target.getAttribute(&#39;ng-bind&#39;));
    }, false);
  }else{
    elems[1].attachEvent(&#39;onkeyup&#39;, function(e) {
      data.value = e.target.value;
      $digest(e.target.getAttribute(&#39;ng-bind&#39;));
    }, false);
  }

  setTimeout(function() {
    data.value = &#39;fuck&#39;;
    /**
     * 这里问啥还要执行$digest这里关键的是需要手动调用$digest方法来启动脏检测
     */
    $digest(&#39;value&#39;);
  }, 2000)

  </script>
</body>
</html>
3. Front-End-Datenentführung (Hijacking)


Die dritte Methode ist Avalon und andere Frameworks Die verwendete Datenhijacking-Methode. Die Grundidee besteht darin, Object.defineProperty zu verwenden, um das Abrufen und Festlegen von Eigenschaften des Datenobjekts zu überwachen. Bei Datenlese- und Zuweisungsvorgängen können die Anweisungen des Knotens am häufigsten verwendet werden . Die spezifische Implementierung lautet wie folgt:

Es ist jedoch zu beachten, dass defineProperty Browser über IE8 unterstützt. Aus Kompatibilitätsgründen können Sie jedoch defineProperty direkt verwenden. Was den IE8-Browser betrifft, müssen zum Hacken noch andere Methoden verwendet werden. Der folgende Code kann IE8 hacken und defineProperty unterstützt IE8. Verwenden Sie beispielsweise einfach es5-shim.js. (Von Browsern unter IE8 ignoriert)
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>data-binding-hijacking</title>
</head>

<body>
  <input q-value="value" type="text" id="input">
  <p q-text="value" id="el"></p>
  <script>


  var elems = [document.getElementById(&#39;el&#39;), document.getElementById(&#39;input&#39;)];

  var data = {
    value: &#39;hello!&#39;
  };

  var command = {
    text: function(str) {
      this.innerHTML = str;
    },
    value: function(str) {
      this.setAttribute(&#39;value&#39;, str);
    }
  };

  var scan = function() {
    /**
     * 扫描带指令的节点属性
     */
    for (var i = 0, len = elems.length; i < len; i++) {
      var elem = elems[i];
      elem.command = [];
      for (var j = 0, len1 = elem.attributes.length; j < len1; j++) {
        var attr = elem.attributes[j];
        if (attr.nodeName.indexOf(&#39;q-&#39;) >= 0) {
          /**
           * 调用属性指令
           */
          command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]);
          elem.command.push(attr.nodeName.slice(2));

        }
      }
    }
  }

  var bValue;
  /**
   * 定义属性设置劫持
   */
  var defineGetAndSet = function(obj, propName) {
    try {
      Object.defineProperty(obj, propName, {

        get: function() {
          return bValue;
        },
        set: function(newValue) {
          bValue = newValue;
          scan();
        },

        enumerable: true,
        configurable: true
      });
    } catch (error) {
      console.log("browser not supported.");
    }
  }
  /**
   * 初始化数据
   */
  scan();

  /**
   * 可以理解为做数据劫持监听
   */
  defineGetAndSet(data, &#39;value&#39;);

  /**
   * 数据绑定监听
   */
  if(document.addEventListener){
    elems[1].addEventListener(&#39;keyup&#39;, function(e) {
      data.value = e.target.value;
    }, false);
  }else{
    elems[1].attachEvent(&#39;onkeyup&#39;, function(e) {
      data.value = e.target.value;
    }, false);
  }

  setTimeout(function() {
    data.value = &#39;fuck&#39;;
  }, 2000)
  </script>
</body>

</html>

4. Zusammenfassung


Zuallererst sind die Beispiele hier nur einfache Implementierungen und können die Ähnlichkeiten tief spüren Unterschiede der drei Methoden, auch komplexe Frameworks durchschneien diese Grundidee.

Das obige ist der detaillierte Inhalt vonTeilen Sie drei Methoden zur Implementierung der bidirektionalen Datenbindung in JavaScript mit. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn