中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

angularjs中臟檢查的示例分析

發布時間:2021-01-21 09:41:48 來源:億速云 閱讀:376 作者:小新 欄目:web開發

小編給大家分享一下angularjs中臟檢查的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

angularjs實現了雙向綁定,與vue的defineProperty不同,它的原理在于它的臟檢查機制,以下做了一些總結;

angular.js介紹

  • AngularJs是mvvm框架,它的組件是vm組件,scope是vm組件的數據集合

  • AngularJs通過directive來聲明vm的行為,它實現為一個watcher,監聽scope的屬性的變化,把最新的屬性更新UI

  • AngularJs的雙向綁定:如:一個是將$scope屬性值綁定到HTML結構中,當$scope屬性值發生變化的時候界面也發生變化;另一個是,當用戶在界面上進行操作,例如點擊、輸入、選擇時,自動觸發$scope屬性的變化(界面也可能跟著變)

  • 監聽scope的屬性變更:臟檢查(dirty check )

臟檢查
  • angular根本不監聽數據的變動,而是在恰當的時機($watch)從$rootScope開始遍歷所有$scope,

  • 檢查它們上面的屬性值是否有變化,如果有變化,就用一個變量dirty記錄為true,再次進行遍歷($digest),

  • 如此往復,直到某一個遍歷完成時,這些$scope的屬性值都沒有變化時,結束遍歷。

  • 由于使用了一個dirty變量作為記錄,因此被稱為臟檢查機制。

簡而言之: 當作用域創建時,angular會去解析模板,將綁定值和事件調用找出來并用$watch綁定;

$scope.$watch(string|function, listener, objectEquality, prettyPrintExpression)
// string: 驗證值或者function執行后return的string
// listener: 如果驗證值不同,則執行該監聽函數
// objectEquality:執行深檢查
  • 完成綁定后,就會自動檢測這些屬性的變化,執行$watch, 那么對應的信息被綁定到angular內部的一個$$watchers中,

  • 它是一個隊列(數組),而當$digest被觸發時,angular就會去遍歷這個數組,

  • 并且用一個dirty變量記錄$$watchers里面記錄的那些$scope屬性是否有變化

接下來的流程:

  • 判斷dirty是否為true,如果為false,則不進行$digest遞歸。(dirty默認為true)

  • 遍歷$$watchers,取出對應的屬性值的老值和新值根據objectEquality進行新老值的對比。

  • 如果兩個值不同,則繼續往下執行。如果兩個值相同,則設置dirty為false。

  • 檢查完所有的watcher之后,如果dirty還為true, 設置dirty為true用新值代替老值;

  • 這樣,在下一輪遞歸的時候,老值就是這一輪的新值再次調用$digest(簡單說就是執行兩次遞歸遍歷檢查新舊值變化)

  • 將變化后的$scope重新渲染到界面

$apply觸發$digest
  • 一般不調用$digest, 調用$apply,它內部會觸發$digest遞歸遍歷

  • angular的內部指令封裝了$apply,比如ng-click,所以一般不用手動調用apply

手動調用apply
  • 部分時候需要手動觸發

function($timeout) {
  // 當我們通過on('click')的方式觸發某些更新的時候,可以這樣做
  $timeout(() => { // 內置語法糖 $http, $timeout已經包含了apply
    $scope.name = 'lily'
  })
  // 也可以這樣做
  $element.on('click', () => {
    $scope.name = 'david'
    $scope.$apply()
  })
}
注意:在遞歸過程中,絕對不能手動調用$apply,比如在ng-click的函數中,比如在$watch的回調函數中。

最后,實現一個簡易臟檢查機制

<!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>

以上是“angularjs中臟檢查的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

类乌齐县| 女性| 昆明市| 冷水江市| 保亭| 平乐县| 定陶县| 贡山| 尉氏县| 万山特区| 界首市| 丁青县| 哈尔滨市| 南岸区| 锡林浩特市| 嘉义县| 邹城市| 肥乡县| 集安市| 建阳市| 习水县| 定边县| 墨竹工卡县| 江华| 页游| 永仁县| 陆丰市| 十堰市| 奉化市| 江城| 子长县| 京山县| 海兴县| 融水| 庐江县| 邮箱| 孝昌县| 通辽市| 景宁| 定陶县| 仪陇县|