AngularJS
дайджест петли прохождение
Поиск…
Синтаксис
- $ scope. $ watch (watchExpression, callback, [deep compare])
- $ Объем. $ Дайджеста ()
- $ Сфера. $ Применять ([ехр])
двусторонняя привязка данных
Угловая магия под капотом. он позволяет связывать DOM с реальными переменными js.
Угловой использует цикл, называемый « цикл дайджеста », который вызывается после любого изменения вызывающих переменную вызовов, которые обновляют DOM.
Например, ng-model
директивы придает keyup
EventListener к этому входу:
<input ng-model="variable" />
Каждый раз, когда срабатывает событие keyup
, начинается цикл дайджест .
В какой-то момент цикл дайджеста выполняет повторный вызов, который обновляет содержимое этого диапазона:
<span>{{variable}}</span>
Основной жизненный цикл этого примера обобщает (очень схематично), как угловые работы ::
- Угловое сканирование html
- Директива
ng-model
создает прослушивательkeyup
на входе -
expression
внутри диапазона добавляет обратный вызов цикла digest
- Директива
- Пользователь взаимодействует со входом
- прослушиватель
keyup
запускает цикл дайджеста - цикл дайджеста вызывает обратный вызов
- Содержимое диапазона обратного вызова
- прослушиватель
$ digest и $ watch
Реализация двухсторонней привязки данных для достижения результата из предыдущего примера может быть выполнена с помощью двух основных функций:
- $ digest вызывается после взаимодействия с пользователем (привязка переменной DOM =>)
- $ watch устанавливает обратный вызов для вызова после изменения переменной (binding variable => DOM)
Примечание: это пример демонстрации, а не фактический угловой код
<input id="input"/>
<span id="span"></span>
Нам нужны две функции:
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() })
}
Теперь мы теперь можем использовать эти функции, чтобы подключить переменную к DOM (угловой поставляется со встроенными директивами, которые сделают это для вас):
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;
});
Вне курса, реальные реализации сложнее и поддерживают такие параметры, как какой элемент привязать и какую переменную использовать
Пример работы можно найти здесь: https://jsfiddle.net/azofxd4j/
дерево $ scope
Предыдущий пример достаточно хорош, если нам нужно связать один элемент html с одной переменной.
В действительности - нам нужно связать многие элементы со многими переменными:
<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>
Этот ng-repeat
связывает 5 элементов с 5 переменными, называемыми number
, с другим значением для каждого из них!
Способ углового достижения такого поведения заключается в использовании отдельного контекста для каждого элемента, который нуждается в отдельных переменных. Этот контекст называется областью.
Каждая область содержит свойства, которые являются переменными, связанными с DOM, а функции $digest
и $watch
реализованы как методы области.
DOM - это дерево, а переменные должны использоваться на разных уровнях дерева:
<div>
<input ng-model="person.name" />
<span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>
Но, как мы видели, контекст (или область) переменных внутри ng-repeat
отличается от контекста над ним. Чтобы решить эту проблему - угловые орудия применения как дерево.
Каждая область имеет массив дочерних элементов, а вызов метода $digest
будет запускать весь метод $digest
своего $digest
метода.
Таким образом - после изменения ввода - $digest
вызывается для области div, которая затем запускает $digest
для своих 5 детей - который обновит его содержимое.
Простая реализация для области видимости может выглядеть так:
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() })
}
Примечание: это пример демонстрации, а не фактический угловой код