久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

AngularJS 數(shù)據(jù)綁定與 $digest 循環(huán) | 天碼營

 菩提與蝸牛 2016-03-15

數(shù)據(jù)綁定可以說是AngularJS最大的特色,。在Angular中,,視圖和模型的數(shù)據(jù)不僅是雙向綁定的,并而且是實(shí)時(shí)的,。 使用Angular可以做到良好的甚至是神奇的用戶體驗(yàn),,例如用戶在輸入表單的過程中實(shí)時(shí)地提示輸入有誤或者輸入正確。

雙向綁定

下圖是模板引擎中常見的單向數(shù)據(jù)綁定:

通常在服務(wù)器端,,將數(shù)據(jù)模型和模板結(jié)合,,生成視圖。當(dāng)視圖中的數(shù)據(jù)發(fā)生改變時(shí),,數(shù)據(jù)模型不會自動更新,;模型發(fā)生改變時(shí),視圖也不會自動刷新,。 因此開發(fā)者不得不寫大量的代碼來同步視圖和模型,。例如:

  • 視圖->模型:綁定DOM事件來監(jiān)聽視圖的改變,進(jìn)而通過javascript函數(shù)來同步數(shù)據(jù)模型,,更改javascript對象,,或者發(fā)送HTTP請求到后臺。
  • 模型->視圖:模型改變時(shí)通過jQuery操作來更新DOM,。如果數(shù)據(jù)模型在后臺,,可能還需要websocket之類的推送機(jī)制。

而Angular提供了雙向的數(shù)據(jù)綁定,,我們可以在Angular Controller的$scope中聲明數(shù)據(jù)模型,,在模板中進(jìn)行綁定。 Angular會自動添加DOM事件,,并在$scope發(fā)生改變時(shí)自動進(jìn)行DOM操作,。下面是Angular雙向綁定的MVT關(guān)系示意圖:

圖片來源: https://docs./guide/databinding

Scope

scope在Angular中代表著應(yīng)用模型,它是模板中表達(dá)式的上下文,。在scope中,你可以watch(監(jiān)聽)表達(dá)式值的變化,,可以傳播事件,。 在編寫控制器時(shí),我們往往會注入一個(gè)$scopeService來設(shè)置當(dāng)前模板的上下文:

var app = angular.module('helloWorldApp', []);
app.controller('worldCtrl', ['$scope', '$http', function($scope, $http) {
    // 在模板上下文中添加一個(gè)變量:username
    $scope.username = 'harttle';
}]);

然后在視圖中綁定它:

<div ng-app='helloWorldApp' ng-controller='worldCtrl'>
  <input type='text' ng-model='username'>
  <span ng-bind='username'>
</div>

ng-model設(shè)置了input內(nèi)容和當(dāng)前上下文中username之間的雙向綁定,;ng-bind設(shè)置了從上下文到span內(nèi)容的綁定,。 當(dāng)我們在input中輸入時(shí),,span的內(nèi)容便會實(shí)時(shí)地改變。

更多$scope的信息請參考: AngularJS 初始化過程

官方文檔: https://docs./api/ng/type/$rootScope.Scope

Scope通信

因?yàn)锳ngular的Controller可以嵌套,,子controller的$scope中可以直接訪問父$scope中的屬性,。 子$scope中可以通過$emit方法來發(fā)射一個(gè)事件,父$scope中通過$on來監(jiān)聽該事件:

// 子Controller中發(fā)射的事件會驗(yàn)證Controller的層級逐級上傳
// 第一個(gè)參數(shù)為事件名,,后面是任意個(gè)數(shù)的參數(shù)
$scope.$emit('alienDestroyed', args, ...)

// 父Controller中通過事件名來監(jiān)聽
$scope.$on('alienDestroyed', function(event, args, ...){});

如果兩個(gè)控制器并非父子關(guān)系,還可以通過$broadcast方法來發(fā)送事件,。 Angular雖然提供了Scope之間的通信機(jī)制,,但濫用事件和通知將會使得你的控制器難以理解和維護(hù)。 如果Controller間有數(shù)據(jù)共享,,把數(shù)據(jù)抽取為Service更加合適,。

$watch

scope中,有時(shí)我們希望監(jiān)聽某個(gè)表達(dá)式的變化,。在Angular的scope中,,監(jiān)聽表達(dá)式的值就像注冊事件處理函數(shù)一樣簡單:

$scope.$watch('username', function(newValue, oldValue){
    console.log('username changed:', oldValue, '->', newValue);
});

是不是很神奇?但是你可能會發(fā)現(xiàn)有時(shí)$watch并不起作用,,這時(shí)你可能需要對Angular Scope中$watch的策略有更多的了解,。Scope有三個(gè)監(jiān)聽方法:

  1. $watch:通過引用(reference)監(jiān)聽,這時(shí)最高效的策略,。只有該表達(dá)式返回值的引用(類似C++的地址)發(fā)生變化時(shí)才會觸發(fā),。
  2. $watchCollection:監(jiān)聽數(shù)組或?qū)ο蟮脑兀ㄒ茫┑淖兓?/li>
  3. $watch(Expression, listener, true):監(jiān)聽值的變化。遞歸地檢測任意深度的屬性變化,,他最方便,,同時(shí)也最低效。

舉個(gè)例子,,模型發(fā)生變化時(shí),,上述三個(gè)方法的監(jiān)聽效果如下圖所示:

圖片來源: https://docs./guide/scope

$digest循環(huán)

曾經(jīng)有過Angular陰謀論,生成Angular是通過無限的循環(huán)來實(shí)時(shí)地刷新視圖,。事實(shí)上Angular要聰明地多,,因?yàn)橹挥胁僮靼l(fā)生時(shí)視圖才需要更新。 而這些有限的用戶操作都會產(chǎn)生DOM事件,,只需監(jiān)聽這些事件便可以做到實(shí)時(shí)地刷新視圖,。

Angular會監(jiān)聽網(wǎng)絡(luò)和DOM事件來自動更新視圖,下面以DOM事件為例來描述Angular如何進(jìn)行視圖的更新:

模板編譯階段

擁有ng-app屬性的HTML元素會成為Angular模板,,在頁面載入時(shí)Angular會對它(以及它的子元素)進(jìn)行編譯(遞歸地匹配directive,、controller并綁定DOM事件)。 主要有兩個(gè)過程(以<input>ng-model為例):

  1. inputDirective找到聲明了ng-model屬性的<input>,,綁定<input>keydown事件,。
  2. inputDirective的上下文($scope)中添加對應(yīng)數(shù)據(jù)模型的$watch函數(shù),,當(dāng)模型改變時(shí)操作并更新DOM。

input是Angular內(nèi)置的一個(gè)Directive,,它會匹配<input>元素,,并對它實(shí)現(xiàn)雙向的數(shù)據(jù)綁定。Angular對幾乎所有輸入型控件都編寫了Directive,。

運(yùn)行階段

  1. 用戶按鍵x,,瀏覽器觸發(fā)了keydown事件。
  2. inputDirective中的事件處理函數(shù)被調(diào)用,,該處理函數(shù)中會執(zhí)行$apply("name = 'x'"),。
  3. Angular 在當(dāng)前$scope中執(zhí)行($eval)表達(dá)式name = 'x',改變數(shù)據(jù)模型,。
  4. Angular 開始$digest循環(huán),。
  5. $digest會調(diào)用所有監(jiān)聽該模型的$watchlistener,這些監(jiān)聽函數(shù)會更新各自負(fù)責(zé)的DOM,。
  6. 瀏覽器重新渲染DOM,。

這時(shí)一個(gè)示意圖:

強(qiáng)制刷新視圖

讓刷新視圖有很多方法:$scope.$digest, $scope.$apply, $timeout。它們有各自的使用情景:

$digest

$digest$scope下的方法,,調(diào)用它會導(dǎo)致當(dāng)前上下文的所有l(wèi)istener被執(zhí)行,。

因?yàn)閘istener可能會改變數(shù)據(jù),因此Angular會一遍一遍地調(diào)用這些listener直到數(shù)據(jù)不再改變,。但我們通常不會使用$digest,,而是使用下面的$apply

$apply

$apply也是$scope下的方法,,它會導(dǎo)致$digest被調(diào)用,。$apply有一個(gè)可選參數(shù)(表達(dá)式字符串)。被調(diào)用時(shí),,傳入的表達(dá)式會被$eval執(zhí)行,,接著$digest會被調(diào)用。

通常我們應(yīng)使用$apply來立即刷新視圖,。既然Angular會進(jìn)行視圖和模型的雙向綁定,,那么什么時(shí)候我們會需要顯式地調(diào)用$apply呢?

Angular監(jiān)聽了DOM事件,、$http事件來刷新視圖,。但當(dāng)我們使用實(shí)現(xiàn)自定義事件(尤其是使用第三方庫)時(shí),事件發(fā)生時(shí)Angular并不知道視圖需要更新,,此時(shí)便需要顯示地調(diào)用$apply,。 例如,Bootstrap事件發(fā)生時(shí)、使用jQuery進(jìn)行AJAX時(shí),,websock  et消息到達(dá)時(shí)。

$timeout

$timeout也是ngModule下的Service,,它是window.setTimeout的包裝,,用來延遲執(zhí)行一個(gè)函數(shù)。當(dāng)我們在Controller中更改了數(shù)據(jù)模型時(shí),,此時(shí)DOM還沒有得到更新($digest循環(huán)還沒開始),。如果我們希望DOM刷新后執(zhí)行某些操作,就可以使用$timeout,。例如:

module.controller('worldCtrl', ['$scope', '$timeout', function($scope, $timeout){
     $scope.users = ['alice', 'bob'];
     $timeout(function(){
         $('.user').tooltip();
     });
}]);

對應(yīng)的模板:

" data-hover-class="active">
<div ng-controller="worldCtrl">
    <span class='user' ng-repeat='user in users'>{{user}}</span>
</div>

當(dāng)$scope.users = ['alice', 'bob'];執(zhí)行后,,DOM中的<span>還不存在,此時(shí)$('.user')的值為空集,。盡管$timeout沒有設(shè)置延遲時(shí)間(第二個(gè)參數(shù)),,但這樣的調(diào)用會使得回調(diào)函數(shù)在$digest循環(huán)之后再執(zhí)行。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多