AngularJs 雙向綁定原理(數(shù)據(jù)綁定機制)

AngularJsscope 模型上設置了一個 監(jiān)聽隊列妙黍,用來監(jiān)聽數(shù)據(jù)變化并更新 view 冕茅。每次綁定一個東西到 view(html) 上時 AngularJs 就會往 $watch 隊列里插入一條 $watch隘竭,用來檢測它監(jiān)視的 model 里是否有變化的東西。當瀏覽器接收到可以被 angular context 處理的事件時绘梦,$digest 循環(huán)就會觸發(fā)嘀掸。$digest 會遍歷所有的 $watch。從而更新DOM实幕。

$watch

這有點類似于我們的觀察者模式吝镣,在當前作用域$scope下,我們創(chuàng)建一個監(jiān)控器$watchers和一個監(jiān)聽器$watch昆庇,$watchers 負責管理所有的 $watch末贾,當我們每次綁定到UI上的時候就自動創(chuàng)建一個$watch,并把它放到 $watchers整吆。

controller.js

app.controller('MainCtrl', function($scope) {
  $scope.Hello = "Hello";
  $scope.world = "World";
});

index.html

<div>{{Hello}}</div>

這里拱撵,即便我們在$scope上添加了兩個變量,但是只有一個綁定在了UI上表蝙,因此在這里只生成了一個$watch

$digest

當瀏覽器接收到可以被angular context處理的事件時拴测,$digest循環(huán)就會觸發(fā)。$digest將會遍歷我們的$watch府蛇,如果$watch沒有變化集索,這個循環(huán)檢測就將停止,如果有至少一個更新過汇跨,這個循環(huán)就會再次觸發(fā)务荆,直到所有的$watch都沒有變化。這樣就能夠保證每個model都已經不會再變化穷遂。這就是臟檢查(Dirty Checking)機制

controller.js

app.controller('MainCtrl', function() {
  $scope.name = "Foo";

  $scope.changeFoo = function() {
      $scope.name = "Bar";
  }
});

index.js

<div>{{ name }}</div>
<button ng-click="changeFoo()">Change the name</button>
  • 當我們按下按鈕
  • 瀏覽器接收到一個事件函匕,進入angular context
  • $digest循環(huán)開始執(zhí)行蚪黑,查詢每個$watch是否變化盅惜。
  • 由于監(jiān)視$scope.name$watch報告了變化,它會強制再執(zhí)行一次$digest循環(huán)祠锣。
  • 新的$digest循環(huán)沒有檢測到變化酷窥。
  • 更新與$scope.name新值相應部分的DOM

$apply

$apply 我們可以直接理解為刷新UI伴网。如果當事件觸發(fā)時蓬推,你調用$apply,它會進入angular context澡腾,如果沒有調用就不會進入沸伏,之后的$digest檢測機制就不會觸發(fā)
app.directive('clickable', function() {
    return {
      restrict: "E",
      scope: {
        foo: '='
      },
      template: '<ul style="background-color: lightblue"><li>{{foo}}</li></ul>',
      link: function(scope, element, attrs) {
        element.bind('click', function() {
          scope.foo++;
          console.log(scope.foo);
        });
      }
    }
});

當我們調用clickable指令的時候糕珊,我們可以看到foo的值增加了,但是界面上顯示的內容并沒有改變毅糟。$digest臟檢測機制沒有觸發(fā)红选,檢測foo$watch就沒有執(zhí)行。

$apply()方法的兩種形式

1) 無參
$scope.$apply();

element.bind('click', function() {
  scope.foo++;
  //if error
  scope.$apply();
});

當我們使用這種形式的時候姆另,如果在scope.$apply之前程序發(fā)生異常喇肋,那scope.$apply沒有執(zhí)行,界面就不會更新

2) 有參
$scope.$apply(function(){
    ...
})

element.bind('click', function() {
  scope.$apply(function() {
      scope.foo++;
  });
})

如果用這種形式迹辐,即使后面的發(fā)生異常蝶防,數(shù)據(jù)還是會更新。

在 AngularJS 中使用 $watch

常用的使用方式:

$scope.name = 'Hello';
$scope.$watch('name', function(newValue, oldValue) {
    if (newValue === oldValue) { return; } 
    $scope.updated++;
});

傳入到$watch()中的第二個參數(shù)是一個回調函數(shù)明吩,該函數(shù)在name的值發(fā)生變化的時候會被調用间学。

如果要監(jiān)聽的是一個對象,那還需要第三個參數(shù):

$scope.data.name = 'Hello';
$scope.$watch('data', function(newValue, oldValue) {
    if (newValue === oldValue) { return; } 
    $scope.updated++;
}, true);

表示比較的是對象的值而不是引用印荔,如果不加第三個參數(shù)true低葫,在 data.name 變化時,不會觸發(fā)相應操作仍律,因為引用的是同一引用嘿悬。

總結

1) 只有在$scope變量綁定到頁面上,才會創(chuàng)建 $watch
2) $apply決定事件是否可以進入angular context
3) $digest 循環(huán)檢查model時最少兩次染苛,最多10次(多于10次拋出異常鹊漠,防止無限檢查)
4) AngularJs自帶的指令已經實現(xiàn)了$apply,所以不需要我們額外的編寫
5) 在自定義指令時茶行,建議使用帶function參數(shù)的$apply
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末躯概,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子畔师,更是在濱河造成了極大的恐慌娶靡,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件看锉,死亡現(xiàn)場離奇詭異姿锭,居然都是意外死亡,警方通過查閱死者的電腦和手機伯铣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門呻此,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腔寡,你說我怎么就攤上這事焚鲜。” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵忿磅,是天一觀的道長糯彬。 經常有香客問我,道長葱她,這世上最難降的妖魔是什么撩扒? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮吨些,結果婚禮上搓谆,老公的妹妹穿的比我還像新娘。我一直安慰自己锤灿,他們只是感情好挽拔,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著但校,像睡著了一般。 火紅的嫁衣襯著肌膚如雪啡氢。 梳的紋絲不亂的頭發(fā)上状囱,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音倘是,去河邊找鬼亭枷。 笑死,一個胖子當著我的面吹牛搀崭,可吹牛的內容都是我干的叨粘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼瘤睹,長吁一口氣:“原來是場噩夢啊……” “哼升敲!你這毒婦竟也來了?” 一聲冷哼從身側響起轰传,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤驴党,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后获茬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體港庄,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年恕曲,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹏氧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡佩谣,死狀恐怖把还,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤笨篷,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布瞳秽,位于F島的核電站,受9級特大地震影響率翅,放射性物質發(fā)生泄漏练俐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一冕臭、第九天 我趴在偏房一處隱蔽的房頂上張望腺晾。 院中可真熱鬧,春花似錦辜贵、人聲如沸悯蝉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鼻由。三九已至,卻和暖如春厚棵,著一層夾襖步出監(jiān)牢的瞬間蕉世,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工婆硬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狠轻,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓彬犯,卻偏偏與公主長得像向楼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谐区,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容