Maison > Article > interface Web > Comprendre la vérification sale dans AngularJS
Recommandations associées : "Tutoriel Angularjs"
angularjs implémente la liaison bidirectionnelle, qui est différente de la définition de propriété de vue. Son principe réside dans son. Le mécanisme de vérification sale est résumé ci-dessous ;
Après avoir terminé la liaison, il détectera automatiquement les changements dans ces propriétés et exécutera $watch Ensuite, les informations correspondantes seront liées à un $$watchers à l'intérieur d'angular. Une file d'attente (tableau), et lorsque $digest est déclenché, angulaire traversera le tableau,En bref : lorsque la portée est créée, angulaire analysera le modèle, découvrira les valeurs de liaisonet les appels d'événements et les liera avec $watch ; 🎜>
$scope.$watch(string|function, listener, objectEquality, prettyPrintExpression) // string: 验证值或者function执行后return的string // listener: 如果验证值不同,则执行该监听函数 // objectEquality:执行深检查
Déterminez si dirty est vrai. S'il est faux, la récursivité $digest ne sera pas effectuée. (Dirty par défaut est true)
Parcourez $$watchers, supprimez l'ancienne valeur et la nouvelle valeur de la valeur d'attribut correspondante et comparez les anciennes et les nouvelles valeurs en fonction de objectEquality.
Si les deux valeurs sont différentes, continuez l'exécution. Si les deux valeurs sont identiques, définissez dirty sur false.
Après avoir vérifié tous les observateurs, si dirty est toujours vrai, définissez dirty sur true et remplacez l'ancienne valeur par la nouvelle valeur
Dans ; de cette façon, lors du prochain cycle de récursion, l'ancienne valeur est la nouvelle valeur de ce tour et appelle à nouveau $digest (en termes simples, il effectue deux parcours récursifs pour vérifier les changements dans les anciennes et les nouvelles valeurs)
La valeur modifiée $scope est restituée à l'interface
$apply déclenche $digest
function($timeout) { // 当我们通过on('click')的方式触发某些更新的时候,可以这样做 $timeout(() => { // 内置语法糖 $http, $timeout已经包含了apply $scope.name = 'lily' }) // 也可以这样做 $element.on('click', () => { $scope.name = 'david' $scope.$apply() }) }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>angularjs脏检查实现</title> </head> <style type="text/css"> button { height: 60px; width: 100px; } p { margin-left: 20px; } </style> <body> <div> <button type="button" ng-click="increase">增加</button> <button type="button" ng-click="decrease">减少</button> 数量:<span ng-bind="data">0</span> </div> <br> </body> <script> window.onload = function () { /** * 声明构造函数 */ function Scope() { this.$$watchList = []; // angular内部会声明一个数组(包含监听的对象),在digest执行时去遍历 } /** * 属性赋值给$scope * 类似angular解析controller的模板,把模板中的属性解析出来,属性赋值给$scope */ Scope.prototype.getNewValue = function () { return $scope[this.name]; } /** * 实现监听 */ Scope.prototype.$watch = function (name, listener) { let watch = { name: name, getNewValue: this.getNewValue, listener: listener || function () { } }; // 当作用域创建时,angular会去解析模板,$watch用来绑定监听值和监听函数 this.$$watchList.push(watch); } /** * 检查dirty,循环更新scope上的最新值 */ Scope.prototype.$digest = function () { console.log('$digest'); let dirty = true; // 默认dirty变量为true let checkTimes = 0; while (dirty) { dirty = this.$valScope(); checkTimes++; if (checkTimes > 10 && dirty) { throw new Error("循环过多"); } } } /** * 验证值是否有变化 */ Scope.prototype.$valScope = function () { let dirty; let list = this.$$watchList; for (let i = 0; i < list.length; i++) { let watch = list[i]; let newValue = watch.getNewValue(); let oldValue = watch.last || undefined; if (newValue !== oldValue) { watch.listener(newValue, oldValue); dirty = true; // 如果新旧值不同,则继续遍历 } else { dirty = false; } watch.last = newValue; } return dirty; } /** * 刷新scope */ Scope.prototype.$apply = function (params) { let list = document.querySelectorAll('[ng-bind]'); console.log('list', list) for (let i = 0, l = list.length; i < l; i++) { let bindData = list[i].getAttribute('ng-bind'); console.log('bindData', bindData) console.log('list[i]', list[i]) list[i].innerHTML = $scope[bindData]; } } let $scope = new Scope(); // 实例化,声明$scope对象集合 $scope.data = 0; $scope.increase = function () { this.data++; }; $scope.decrease = function () { this.data--; }; $scope.$watch('data', function(newValue, oldValue) { // 监听 console.log("new: " + newValue + "=========" + "old: " + oldValue); }); // 手动为button按钮添加onclick事件,并为通过闭包为其绑定了全局scope对象,绑定apply方法 // 类似angular内部实现 function startBind() { let list = document.querySelectorAll('[ng-click]'); for (let i = 0, l = list.length; i < l; i++) { list[i].onclick = (function (index) { return function () { let func = this.getAttribute('ng-click'); $scope[func]($scope); $scope.$digest(); $scope.$apply() } })(i) } } // 初始化 startBind(); } </script> </html>
! !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!