AngularJS
sintesi del ciclo digest
Ricerca…
Sintassi
- $ scope. $ watch (watchExpression, callback, [deep compare])
- $ Portata. $ Digest ()
- $ Portata. $ Applicare ([exp])
associazione dati bidirezionale
Angolare ha un po 'di magia sotto il suo cappuccio. abilita il DOM vincolante a variabili js reali.
Angular utilizza un ciclo, denominato " ciclo digest ", che viene chiamato dopo ogni modifica di una variabile, chiamando callback che aggiornano il DOM.
Ad esempio, la direttiva ng-model
allega un eventup di keyup
a questo input:
<input ng-model="variable" />
Ogni volta che si keyup
evento keyup
, viene keyup
il ciclo digest .
Ad un certo punto, il ciclo digest itera su un callback che aggiorna il contenuto di questo intervallo:
<span>{{variable}}</span>
Il ciclo di vita di base di questo esempio, riassume (molto schematicamente) come funziona l'angolare:
- Scansioni angolari html
- direttiva
ng-model
crea un listenerkeyup
sull'input -
expression
inside span aggiunge un callback al ciclo digest
- direttiva
- L'utente interagisce con l'input
- ascoltatore di
keyup
inizia il ciclo di digestione - il ciclo di digest chiama il callback
- Gli aggiornamenti del callback comprendono i contenuti
- ascoltatore di
$ digest e $ watch
L'implementazione del binding dei dati a due vie, per ottenere il risultato dell'esempio precedente, potrebbe essere eseguita con due funzioni principali:
- $ digest è chiamato dopo un'interazione dell'utente (vincolante DOM => variabile)
- $ watch imposta un callback da chiamare dopo le modifiche alle variabili (binding variable => DOM)
nota: questo è un esempio è una dimostrazione, non il codice angolare reale
<input id="input"/>
<span id="span"></span>
Le due funzioni di cui abbiamo bisogno:
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() })
}
Ora potremmo usare queste funzioni per collegare una variabile al DOM (l'angolare viene fornito con direttive incorporate che faranno questo per voi):
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;
});
Fuori rotta, le implementazioni reali sono più complesse e supportano parametri come l' elemento a cui legarsi e quale variabile utilizzare
Un esempio in esecuzione può essere trovato qui: https://jsfiddle.net/azofxd4j/
l'albero $ scope
L'esempio precedente è abbastanza buono quando è necessario associare un singolo elemento html a una singola variabile.
In realtà, abbiamo bisogno di legare molti elementi a molte variabili:
<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>
Questa ng-repeat
lega 5 elementi a 5 variabili chiamate number
, con un valore diverso per ognuna di esse!
Il modo in cui l'angolare raggiunge questo comportamento sta usando un contesto separato per ogni elemento che ha bisogno di variabili separate. Questo contesto è chiamato scope.
Ogni ambito contiene proprietà, che sono le variabili legate al DOM, e le funzioni $digest
e $watch
sono implementate come metodi dell'ambito.
Il DOM è un albero e le variabili devono essere utilizzate in diversi livelli dell'albero:
<div>
<input ng-model="person.name" />
<span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>
Ma come abbiamo visto, il contesto (o l'ambito) delle variabili all'interno di ng-repeat
è diverso dal contesto sopra di esso. Per risolvere questo - gli ambiti angolari implementa un albero.
Ogni ambito ha una serie di figli, e chiamando i suoi $digest
metodo verrà eseguito tutti i dei suoi figli $digest
metodo.
In questo modo - dopo aver modificato l'input - viene chiamato $digest
per l'ambito div, che quindi esegue $digest
per i suoi 5 figli - che aggiornerà il suo contenuto.
Un'implementazione semplice per un ambito potrebbe essere simile a questa:
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() })
}
nota: questo è un esempio è una dimostrazione, non il codice angolare reale