最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Angular JS數(shù)據(jù)的雙向綁定詳解及實例

 更新時間:2016年12月31日 09:26:01   投稿:lqh  
這篇文章主要介紹了Angular JS數(shù)據(jù)的雙向綁定詳解及實例的相關(guān)資料,需要的朋友可以參考下

Angular JS數(shù)據(jù)的雙向綁定

接觸AngularJS許了,時常問自己一些問題,如果是我實現(xiàn)它,會在哪些方面選擇跟它相同的道路,哪些方面不同。為此,記錄了一些思考,給自己回顧,也供他人參考。

初步大致有以下幾個方面:

  • 數(shù)據(jù)雙向綁定
  • 視圖模型的繼承關(guān)系
  • 模塊和依賴注入的設(shè)計
  • 待定

數(shù)據(jù)的雙向綁定

Angular實現(xiàn)了雙向綁定機(jī)制。所謂的雙向綁定,無非是從界面的操作能實時反映到數(shù)據(jù),數(shù)據(jù)的變更能實時展現(xiàn)到界面。

一個最簡單的示例就是這樣:

<div ng-controller="CounterCtrl">
  <span ng-bind="counter"></span>
  <button ng-click="counter=counter+1">increase</button>
</div>
function CounterCtrl($scope) {
  $scope.counter = 1;
}

這個例子很簡單,毫無特別之處,每當(dāng)點擊一次按鈕,界面上的數(shù)字就增加一。

綁定數(shù)據(jù)是怎樣生效的

初學(xué)AngularJS的人可能會踩到這樣的坑,假設(shè)有一個指令:

var app = angular.module("test", []);

app.directive("myclick", function() {
  return function (scope, element, attr) {
    element.on("click", function() {
      scope.counter++;
    });
  };
});

app.controller("CounterCtrl", function($scope) {
  $scope.counter = 0;
});
<body ng-app="test">
  <div ng-controller="CounterCtrl">
    <button myclick>increase</button>
    <span ng-bind="counter"></span>
  </div>
</body>

這個時候,點擊按鈕,界面上的數(shù)字并不會增加。很多人會感到迷惑,因為他查看調(diào)試器,發(fā)現(xiàn)數(shù)據(jù)確實已經(jīng)增加了,Angular不是雙向綁定嗎,為什么數(shù)據(jù)變化了,界面沒有跟著刷新?

試試在scope.counter++;這句之后加一句scope.digest();再看看是不是好了?

為什么要這么做呢,什么情況下要這么做呢?我們發(fā)現(xiàn)第一個例子中并沒有digest,而且,如果你寫了digest,它還會拋出異常,說正在做其他的digest,這是怎么回事?

我們先想想,假如沒有AngularJS,我們想要自己實現(xiàn)這么個功能,應(yīng)該怎樣?

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>two-way binding</title>
  </head>
  <body onload="init()">
    <button ng-click="inc">
      increase 1
    </button>
    <button ng-click="inc2">
      increase 2
    </button>
    <span style="color:red" ng-bind="counter"></span>
    <span style="color:blue" ng-bind="counter"></span>
    <span style="color:green" ng-bind="counter"></span>

    <script type="text/javascript">
      /* 數(shù)據(jù)模型區(qū)開始 */
      var counter = 0;

      function inc() {
        counter++;
      }

      function inc2() {
        counter+=2;
      }
      /* 數(shù)據(jù)模型區(qū)結(jié)束 */

      /* 綁定關(guān)系區(qū)開始 */
      function init() {
        bind();
      }

      function bind() {
        var list = document.querySelectorAll("[ng-click]");
        for (var i=0; i<list.length; i++) {
          list[i].onclick = (function(index) {
            return function() {
              window[list[index].getAttribute("ng-click")]();
              apply();
            };
          })(i);
        }
      }

      function apply() {
        var list = document.querySelectorAll("[ng-bind='counter']");
        for (var i=0; i<list.length; i++) {
          list[i].innerHTML = counter;
        }
      }
      /* 綁定關(guān)系區(qū)結(jié)束 */
    </script>
  </body>
</html>

可以看到,在這么一個簡單的例子中,我們做了一些雙向綁定的事情。從兩個按鈕的點擊到數(shù)據(jù)的變更,這個很好理解,但我們沒有直接使用DOM的onclick方法,而是搞了一個ng-click,然后在bind里面把這個ng-click對應(yīng)的函數(shù)拿出來,綁定到onclick的事件處理函數(shù)中。為什么要這樣呢?因為數(shù)據(jù)雖然變更了,但是還沒有往界面上填充,我們需要在此做一些附加操作。

從另外一個方面看,當(dāng)數(shù)據(jù)變更的時候,需要把這個變更應(yīng)用到界面上,也就是那三個span里。但由于Angular使用的是臟檢測,意味著當(dāng)改變數(shù)據(jù)之后,你自己要做一些事情來觸發(fā)臟檢測,然后再應(yīng)用到這個數(shù)據(jù)對應(yīng)的DOM元素上。問題就在于,怎樣觸發(fā)臟檢測?什么時候觸發(fā)?

我們知道,一些基于setter的框架,它可以在給數(shù)據(jù)設(shè)值的時候,對DOM元素上的綁定變量作重新賦值。臟檢測的機(jī)制沒有這個階段,它沒有任何途徑在數(shù)據(jù)變更之后立即得到通知,所以只能在每個事件入口中手動調(diào)用apply(),把數(shù)據(jù)的變更應(yīng)用到界面上。在真正的Angular實現(xiàn)中,這里先進(jìn)行臟檢測,確定數(shù)據(jù)有變化了,然后才對界面設(shè)值。

所以,我們在ng-click里面封裝真正的click,最重要的作用是為了在之后追加一次apply(),把數(shù)據(jù)的變更應(yīng)用到界面上去。

那么,為什么在ng-click里面調(diào)用$digest的話,會報錯呢?因為Angular的設(shè)計,同一時間只允許一個$digest運(yùn)行,而ng-click這種內(nèi)置指令已經(jīng)觸發(fā)了$digest,當(dāng)前的還沒有走完,所以就出錯了。

$digest和$apply

在Angular中,有$apply和$digest兩個函數(shù),我們剛才是通過$digest來讓這個數(shù)據(jù)應(yīng)用到界面上。但這個時候,也可以不用$digest,而是使用$apply,效果是一樣的,那么,它們的差異是什么呢?

最直接的差異是,$apply可以帶參數(shù),它可以接受一個函數(shù),然后在應(yīng)用數(shù)據(jù)之后,調(diào)用這個函數(shù)。所以,一般在集成非Angular框架的代碼時,可以把代碼寫在這個里面調(diào)用。

var app = angular.module("test", []);

app.directive("myclick", function() {
  return function (scope, element, attr) {
    element.on("click", function() {
      scope.counter++;
      scope.$apply(function() {
        scope.counter++;
      });
    });
  };
});

app.controller("CounterCtrl", function($scope) {
  $scope.counter = 0;
});

除此之外,還有別的區(qū)別嗎?

在簡單的數(shù)據(jù)模型中,這兩者沒有本質(zhì)差別,但是當(dāng)有層次結(jié)構(gòu)的時候,就不一樣了??紤]到有兩層作用域,我們可以在父作用域上調(diào)用這兩個函數(shù),也可以在子作用域上調(diào)用,這個時候就能看到差別了。

對于$digest來說,在父作用域和子作用域上調(diào)用是有差別的,但是,對于$apply來說,這兩者一樣。我們來構(gòu)造一個特殊的示例:

var app = angular.module("test", []);

app.directive("increasea", function() {
  return function (scope, element, attr) {
    element.on("click", function() {
      scope.a++;
      scope.$digest();
    });
  };
});

app.directive("increaseb", function() {
  return function (scope, element, attr) {
    element.on("click", function() {
      scope.b++;
      scope.$digest();  //這個換成$apply即可
    });
  };
});

app.controller("OuterCtrl", ["$scope", function($scope) {
  $scope.a = 1;

  $scope.$watch("a", function(newVal) {
    console.log("a:" + newVal);
  });

  $scope.$on("test", function(evt) {
    $scope.a++;
  });
}]);

app.controller("InnerCtrl", ["$scope", function($scope) {
  $scope.b = 2;

  $scope.$watch("b", function(newVal) {
    console.log("b:" + newVal);
    $scope.$emit("test", newVal);
  });
}]);
<div ng-app="test">
  <div ng-controller="OuterCtrl">
    <div ng-controller="InnerCtrl">
      <button increaseb>increase b</button>
      <span ng-bind="b"></span>
    </div>
    <button increasea>increase a</button>
    <span ng-bind="a"></span>
  </div>
</div> 


這時候,我們就能看出差別了,在increase b按鈕上點擊,這時候,a跟b的值其實都已經(jīng)變化了,但是界面上的a沒有更新,直到點擊一次increase a,這時候剛才對a的累加才會一次更新上來。怎么解決這個問題呢?只需在increaseb這個指令的實現(xiàn)中,把$digest換成$apply即可。

當(dāng)調(diào)用$digest的時候,只觸發(fā)當(dāng)前作用域和它的子作用域上的監(jiān)控,但是當(dāng)調(diào)用$apply的時候,會觸發(fā)作用域樹上的所有監(jiān)控。

因此,從性能上講,如果能確定自己作的這個數(shù)據(jù)變更所造成的影響范圍,應(yīng)當(dāng)盡量調(diào)用$digest,只有當(dāng)無法精確知道數(shù)據(jù)變更造成的影響范圍時,才去用$apply,很暴力地遍歷整個作用域樹,調(diào)用其中所有的監(jiān)控。

從另外一個角度,我們也可以看到,為什么調(diào)用外部框架的時候,是推薦放在$apply中,因為只有這個地方才是對所有數(shù)據(jù)變更都應(yīng)用的地方,如果用$digest,有可能臨時丟失數(shù)據(jù)變更。

臟檢測的利弊

很多人對Angular的臟檢測機(jī)制感到不屑,推崇基于setter,getter的觀測機(jī)制,在我看來,這只是同一個事情的不同實現(xiàn)方式,并沒有誰完全勝過誰,兩者是各有優(yōu)劣的。

大家都知道,在循環(huán)中批量添加DOM元素的時候,會推薦使用DocumentFragment,為什么呢,因為如果每次都對DOM產(chǎn)生變更,它都要修改DOM樹的結(jié)構(gòu),性能影響大,如果我們能先在文檔碎片中把DOM結(jié)構(gòu)創(chuàng)建好,然后整體添加到主文檔中,這個DOM樹的變更就會一次完成,性能會提高很多。

同理,在Angular框架里,考慮到這樣的場景:

function TestCtrl($scope) {
  $scope.numOfCheckedItems = 0;

  var list = [];

  for (var i=0; i<10000; i++) {
    list.push({
      index: i,
      checked: false
    });
  }

  $scope.list = list;

  $scope.toggleChecked = function(flag) {
    for (var i=0; i<list.length; i++) {
      list[i].checked = flag;
      $scope.numOfCheckedItems++;
    }
  };
}

如果界面上某個文本綁定這個numOfCheckedItems,會怎樣?在臟檢測的機(jī)制下,這個過程毫無壓力,一次做完所有數(shù)據(jù)變更,然后整體應(yīng)用到界面上。這時候,基于setter的機(jī)制就慘了,除非它也是像Angular這樣把批量操作延時到一次更新,否則性能會更低。

所以說,兩種不同的監(jiān)控方式,各有其優(yōu)缺點,最好的辦法是了解各自使用方式的差異,考慮出它們性能的差異所在,在不同的業(yè)務(wù)場景中,避開最容易造成性能瓶頸的用法。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

  • angular十大常見問題

    angular十大常見問題

    本文主要介紹了angular十大常見問題,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • AngularJS Controller作用域

    AngularJS Controller作用域

    這篇文章主要為大家詳細(xì)介紹了AngularJS Controller的作用域,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • AngularJS 實現(xiàn)JavaScript 動畫效果詳解

    AngularJS 實現(xiàn)JavaScript 動畫效果詳解

    本文主要介紹AngularJS 實現(xiàn) JavaScript 動畫的資料,這里整理了詳細(xì)的資料和簡單示例代碼,有興趣的小伙伴可以參考下
    2016-09-09
  • Angular?Tree?Shaking優(yōu)化機(jī)制原理詳解

    Angular?Tree?Shaking優(yōu)化機(jī)制原理詳解

    這篇文章主要為大家介紹了Angular?Tree?Shaking優(yōu)化機(jī)制原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Angular中封裝fancyBox(圖片預(yù)覽)遇到問題小結(jié)

    Angular中封裝fancyBox(圖片預(yù)覽)遇到問題小結(jié)

    這篇文章主要介紹了Angular中封裝fancyBox(圖片預(yù)覽)遇到的問題小結(jié),需要的朋友可以參考下
    2017-09-09
  • angularJS實現(xiàn)表格部分列展開縮起示例代碼

    angularJS實現(xiàn)表格部分列展開縮起示例代碼

    這篇文章主要介紹了angularJS實現(xiàn)表格部分列展開縮起示例代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • AngularJS基礎(chǔ)學(xué)習(xí)筆記之指令

    AngularJS基礎(chǔ)學(xué)習(xí)筆記之指令

    指令(Directives)是所有AngularJS應(yīng)用最重要的部分。盡管AngularJS已經(jīng)提供了非常豐富的指令,但還是經(jīng)常需要創(chuàng)建應(yīng)用特定的指令。這篇教程會為你講述如何自定義指令,以及介紹如何在實際項目中使用。
    2015-05-05
  • Angular.js實現(xiàn)多個checkbox只能選擇一個的方法示例

    Angular.js實現(xiàn)多個checkbox只能選擇一個的方法示例

    這篇文章主要給大家介紹了利用Angular.js實現(xiàn)多個checkbox只能選擇一個的方法,文中給出了詳細(xì)的示例代碼,相信對大家具有一定的參考價值,下面來一起看看吧。
    2017-02-02
  • AngularJS中directive指令使用之事件綁定與指令交互用法示例

    AngularJS中directive指令使用之事件綁定與指令交互用法示例

    這篇文章主要介紹了AngularJS中directive指令使用之事件綁定與指令交互用法,結(jié)合實例形式分析了directive指令在模板的使用,事件的綁定及元素、屬性、控制器之間的交互相關(guān)操作技巧,需要的朋友可以參考下
    2016-11-11
  • SeaJS 與 RequireJS 的差異對比

    SeaJS 與 RequireJS 的差異對比

    這篇文章主要介紹了SeaJS 與 RequireJS 的差異對比,本文主要對CMD規(guī)范和AMD規(guī)范的弊端做了對比,并做出了一個總結(jié),需要的朋友可以參考下
    2014-12-12

最新評論

镇江市| 闸北区| 崇州市| 易门县| 江陵县| 精河县| 普兰店市| 迁安市| 阳信县| 商都县| 丁青县| 安福县| 夹江县| 晋宁县| 宁南县| 元阳县| 新密市| 惠水县| 乐至县| 达日县| 新和县| 格尔木市| 南丹县| 龙山县| 河北省| 延长县| 壤塘县| 鱼台县| 旌德县| 运城市| 林周县| 偏关县| 海宁市| 五家渠市| 大方县| 武义县| 布尔津县| 简阳市| 祁连县| 成武县| 鄄城县|