Это скорее второй подход.
Угловой делает все, что нужно, тяжелый подъем через директивы. Практически все, что вы используете в угловому директива:
<div ng-app>
<div ng-controller>
<button ng-click>
<!-- input is actually a directive -->
<input ng-model="foo" />
Все эти маленькие директивы получить ссылку на элемент DOM, к которому они присоединены, а также $scope
объекта. Директивы просто регистрируют обратный вызов, который должен выполняться, когда что-то меняется.
Как вы уже отметили, это называется наблюдателями.
Область является иерархической, поэтому всегда существует дерево связанных объектов, которые составляют ваше состояние приложения. Когда начинается цикл $digest
, он рекурсивно ходит по дереву, ищущему изменения, и отбрасывает обратные вызовы (aka watchers).
Обратный вызов может затем сделать все, что захочет. Просто в большинстве случаев он обновляет DOM.
В конце дня действительно нет ничего волшебного в том, как это происходит. Просто структура обратных вызовов, которые выполняются, когда что-то меняется.
Вот глупый пример пользовательской директивы, которая регистрирует наблюдателя и обновляет DOM при изменении какого-либо свойства.
(function(){
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function updateValue(){
return {
restrict:'A',
link: function(scope, elem, attrs){
elem.on('click', function(){
//You would never actually do this, but
// it's a demo
scope[attrs.updateValue] = "rgb(" +
getRandomInt(0, 255) + "," +
getRandomInt(0, 255) + "," +
getRandomInt(0, 255) + ")";
//kick off a digest loop manually
// this is similar to what a lot of angular
// directives do.
scope.$digest();
});
}
};
}
function sillyDomChangeOn(){
return {
restrict:'A',
link: function(scope, elem, attrs){
scope.$watch(attrs.sillyDomChangeOn, function(newVal, oldVal){
elem.css('color', newVal);
});
}
};
}
angular.module('my-app', [])
.directive('updateValue', updateValue)
.directive('sillyDomChangeOn', sillyDomChangeOn);
}());
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css">
<div ng-app="my-app" class="container">
<button type="button" class="btn btn-primary" update-value="randomVal">Update Value</button>
<h3>Value: <code>{{randomVal}}</code></h3>
<div class="well" silly-dom-change-on="randomVal">
<h3>This is just a random DIV</h3>
<div>
</div>
Спасибо! Теперь, когда вы объяснили это, это имеет смысл, но я изначально забыл о том, как цикл дайджеста связан с директивами. Теперь я понимаю, что он (часто) вызывается внутри директивы, где он имеет доступ к элементу DOM (_that's_ как он обращается к элементу DOM!). Соответствующая ссылка на источник [ngBind] (https://github.com/angular/angular.js/blob/master/src/ng/directive/ngBind.js#L63). –