Maison  >  Article  >  interface Web  >  Comprendre la vérification sale dans AngularJS

Comprendre la vérification sale dans AngularJS

青灯夜游
青灯夜游avant
2021-01-20 17:26:301925parcourir

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 ;

Introduction à angulaire.js

  • AngularJs est un framework mvvm, son composant est le composant vm et sa portée est la collecte de données de la vm. composant
  • AngularJs déclare le comportement de la vm via la directive, qui est implémentée en tant qu'observateur, surveille les modifications dans les propriétés de la portée et met à jour l'interface utilisateur avec les dernières propriétés
  • Bidirectionnel liaison d'AngularJs : par exemple : l'une consiste à mettre $ La valeur de l'attribut scope est liée à la structure HTML. Lorsque la valeur de l'attribut $scope change, l'interface change également lorsque l'utilisateur effectue des opérations sur l'interface. en cliquant, en saisissant et en sélectionnant, l'attribut $scope est automatiquement déclenché. Modifications (l'interface peut également changer)
  • Surveiller les modifications de l'attribut de portée : vérification sale (dirty check)

Dirty check

  • angular n'écoute pas du tout les changements de données, mais au bon moment ($watch), parcourez tous les $scopes à partir de $rootScope,
  • vérifiez si l'attribut les valeurs sur eux ont changé, s'il y a des changements, utilisez une variable sale pour l'enregistrer comme vrai, parcourez ($digest) à nouveau,
  • et ainsi de suite, jusqu'à ce qu'un certain parcours soit terminé et que le les valeurs d'attribut de ces $scopes n'ont pas changé, le parcours se termine.
  • Parce qu'une variable sale est utilisée comme enregistrement, on l'appelle un mécanisme de vérification sale.

En bref : lorsque la portée est créée, angulaire analysera le modèle, découvrira les valeurs de liaison​​et les appels d'événements et les liera avec $watch ; 🎜>

$scope.$watch(string|function, listener, objectEquality, prettyPrintExpression)
// string: 验证值或者function执行后return的string
// listener: 如果验证值不同,则执行该监听函数
// objectEquality:执行深检查

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,
  • et utilisera une variable sale pour enregistrer si les attributs $scope enregistrés dans $$watchers ont changé
  • Le processus suivant :

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

Généralement, $digest n'est pas appelé , l'appel de $apply déclenchera en interne le parcours récursif de $digest

les instructions internes d'angular encapsulent $apply, comme ng-click, il n'est donc généralement pas nécessaire d'appeler manuellement apply
  • Appeler manuellement apply
Parfois, il est nécessaire Déclencher manuellement

function($timeout) {
  // 当我们通过on('click')的方式触发某些更新的时候,可以这样做
  $timeout(() => { // 内置语法糖 $http, $timeout已经包含了apply
    $scope.name = 'lily'
  })
  // 也可以这样做
  $element.on('click', () => {
    $scope.name = 'david'
    $scope.$apply()
  })
}
    Remarque : Pendant le processus récursif, $apply ne doit pas être appelé manuellement, comme dans le ng- fonction click, comme dans la fonction de rappel de $watch.
  • Enfin, implémentez un simple mécanisme de vérification sale
<!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(&#39;$digest&#39;);
      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(&#39;[ng-bind]&#39;);
      console.log(&#39;list&#39;, list)
      for (let i = 0, l = list.length; i < l; i++) {
        let bindData = list[i].getAttribute(&#39;ng-bind&#39;);
        console.log(&#39;bindData&#39;, bindData)
        console.log(&#39;list[i]&#39;, 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(&#39;data&#39;, function(newValue, oldValue) { // 监听
        console.log("new: " + newValue + "=========" + "old: " + oldValue);
    });


    // 手动为button按钮添加onclick事件,并为通过闭包为其绑定了全局scope对象,绑定apply方法
    // 类似angular内部实现
    function startBind() {
      let list = document.querySelectorAll(&#39;[ng-click]&#39;);
      for (let i = 0, l = list.length; i < l; i++) {
        list[i].onclick = (function (index) {
          return function () {
            let func = this.getAttribute(&#39;ng-click&#39;);
            $scope[func]($scope);
            $scope.$digest();
            $scope.$apply()
          }
        })(i)
      }
    }

    // 初始化
    startBind();
  }

</script>

</html>
Pour plus de connaissances liées à la programmation, veuillez visiter :
Vidéo de programmation

 ! !

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer