Suche…


Syntax

  • $ scope. $ watch (watchExpression, Rückruf, [Deep Compare])
  • $ scope. $ digest ()
  • $ scope. $ apply ([exp])

Zweiwege-Datenbindung

Angular hat etwas Magie unter der Haube. Es ermöglicht das Binden von DOM an reale js-Variablen.

Angular verwendet eine Schleife mit dem Namen " Digest Loop ", die nach jeder Änderung einer Variablen aufgerufen wird - Callbacks, die das DOM aktualisieren.

Zum Beispiel fügt die Direktive ng-model dieser Eingabe einen keyup eventListener hinzu :

<input ng-model="variable" />

Jedes Mal, keyup das keyup Ereignis keyup wird, beginnt die Digest-Schleife .

Irgendwann durchläuft die Digest-Schleife einen Rückruf, der den Inhalt dieses Bereichs aktualisiert:

<span>{{variable}}</span>

Der grundlegende Lebenszyklus dieses Beispiels fasst (sehr schematisch) die Wirkungsweise von Winkel zusammen:

  1. Angular scannt HTML
    • ng-model Direktive ng-model erstellt bei der Eingabe einen keyup Listener
    • expression innerhalb des Bereichs fügt dem Digest-Zyklus einen Rückruf hinzu
  2. Der Benutzer interagiert mit der Eingabe
    • keyup listener startet den Digest-Zyklus
    • Digest-Zyklus ruft den Rückruf auf
    • Callback-Aktualisierungen umfassen den Inhalt

$ Digest und $ Watch

Die Implementierung der bidirektionalen Datenbindung zum Erreichen des Ergebnisses aus dem vorherigen Beispiel könnte mit zwei Kernfunktionen erfolgen:

  • $ digest wird nach einer Benutzerinteraktion aufgerufen (bindendes DOM => variable)
  • $ watch setzt einen Callback, der nach Variablenänderungen aufgerufen wird (Bindungsvariable => DOM)

Hinweis: Bei diesem Beispiel handelt es sich um eine Demonstration, nicht um den tatsächlichen Winkelcode


<input id="input"/>
<span id="span"></span>

Die zwei Funktionen, die wir brauchen:

var $watches = [];
function $digest(){
    $watches.forEach(function($w){
        var val = $w.val();
        if($w.prevVal !== val){
            $w.callback(val, $w.prevVal);
            $w.prevVal = val;
        }
    })
}
function $watch(val, callback){
    $watches.push({val:val, callback:callback, prevVal: val() })
}

Jetzt können wir diese Funktionen verwenden, um eine Variable an das DOM anzuschließen.

var realVar;    
//this is usually done by ng-model directive
input1.addEventListener('keyup',function(e){
    realVar=e.target.value; 
    $digest()
}, true);

//this is usually done with {{expressions}} or ng-bind directive
$watch(function(){return realVar},function(val){
    span1.innerHTML = val;
});

Natürlich sind die realen Implementierungen komplexer und unterstützen Parameter wie das zu bindende Element und die zu verwendende Variable

Ein laufendes Beispiel finden Sie hier: https://jsfiddle.net/azofxd4j/

der $ scope-Baum

Das vorige Beispiel ist gut genug, wenn wir ein einzelnes HTML-Element an eine einzelne Variable binden müssen.

In der Realität müssen viele Elemente an viele Variablen gebunden werden:

<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>

Diese ng-repeat bindet 5 Elemente an 5 Variablen, die als number , und für jeden von ihnen einen anderen Wert!


Die Art und Weise, wie Winkel dieses Verhalten erreicht, verwendet einen separaten Kontext für jedes Element, das separate Variablen benötigt. Dieser Kontext wird als Bereich bezeichnet.

Jeder Bereich enthält Eigenschaften, dh die an das DOM gebundenen Variablen. Die Funktionen $digest und $watch werden als Methoden des Bereichs implementiert.

Das DOM ist eine Baumstruktur, und Variablen müssen in verschiedenen Ebenen der Baumstruktur verwendet werden:

<div>
    <input ng-model="person.name" />
    <span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>

Wie wir jedoch sahen, unterscheidet sich der Kontext (oder Geltungsbereich) von Variablen in ng-repeat von dem darüber liegenden Kontext. Um dies zu lösen, werden Winkelbereiche als Baum implementiert.

Jeder Bereich verfügt über ein Array von $digest Elementen. Wenn Sie seine $digest Methode aufrufen, werden alle deren $digest Methoden ausgeführt.

Auf diese Weise wird - nach Änderung der Eingabe - $digest für den Gültigkeitsbereich der div aufgerufen, der dann den $digest für seine 5 Kinder ausführt, wodurch der Inhalt aktualisiert wird.


Eine einfache Implementierung für einen Bereich könnte folgendermaßen aussehen:

function $scope(){
    this.$children = [];
    this.$watches = [];
}

$scope.prototype.$digest = function(){
    this.$watches.forEach(function($w){
        var val = $w.val();
        if($w.prevVal !== val){
            $w.callback(val, $w.prevVal);
          $w.prevVal = val;
        }
    });
    this.$children.forEach(function(c){
        c.$digest();
    });
}

$scope.prototype.$watch = function(val, callback){
    this.$watches.push({val:val, callback:callback, prevVal: val() })
}

Hinweis: Bei diesem Beispiel handelt es sich um eine Demonstration, nicht um den tatsächlichen Winkelcode



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow