摘要:什么是AngularJS 首先AngularJS是一個(gè)框架,框架與函數(shù)庫(kù)的區(qū)別就在于,框架決定整個(gè)項(xiàng)目的開發(fā)套路,以框架為主導(dǎo),函數(shù)庫(kù)卻是以項(xiàng)目本身為主導(dǎo),例如jquery。它就是個(gè)雙向數(shù)據(jù)綁定的前端JS框架,雙向數(shù)據(jù)綁定是相比較于其他框架最特別的地方,其他特性都是圍繞它工作的。它適用于CRUD應(yīng)用(增加(Create)、讀取(Retrieve)、更新(Upd
什么是AngularJS
首先AngularJS是一個(gè)框架,框架與函數(shù)庫(kù)的區(qū)別就在于,框架決定整個(gè)項(xiàng)目的開發(fā)套路,以框架為主導(dǎo),函數(shù)庫(kù)卻是以項(xiàng)目本身為主導(dǎo),例如jquery。它就是個(gè)雙向數(shù)據(jù)綁定的前端JS框架,雙向數(shù)據(jù)綁定是相比較于其他框架最特別的地方,其他特性都是圍繞它工作的。它適用于CRUD應(yīng)用(增加(Create)、讀取(Retrieve)、更新(Update)和刪除(Delete))。
PS:圖例意思是當(dāng)模板編譯成視圖,視圖發(fā)生變化觸發(fā)數(shù)據(jù)模型變化,數(shù)據(jù)模型又會(huì)作用于視圖。
我時(shí)常想著一句話“當(dāng)你知道一個(gè)工具的30%,你就能用它做70%的事”,所以學(xué)習(xí)一個(gè)框架的時(shí)候,不需要完完整整從頭看到尾,當(dāng)了解差不多了就可以開始干活。開始學(xué)習(xí)AngularJS,只需知道什么是雙向數(shù)據(jù)綁定就行了,這是最關(guān)鍵、最需明白的。
寫一個(gè)簡(jiǎn)單的示例如下。
HTML:
<!doctype html> <html ng-app> <head> <meta charset="utf-8"> <script src="angular.js"></script> <script src="HelloAngular_bind.js"></script> </head> <body> <div ng-controller="HelloAngular"> <p>x :<input type="text" ng-model="x" /></p> <p>y :<input type="text" ng-model="y" /></p> <p>x + y :<span ng-bind="x*1+y*1"></span></p> </div> </body> </html>
JS:
function HelloAngular($scope) { $scope.x = 1; $scope.y = 2; }
PS:例子感受一下就行,沒有必要深究,但應(yīng)該對(duì)data與view的互相影響有些感覺。
AngularJS有什么
除了最重要的雙向數(shù)據(jù)綁定,AngularJS有以下元件,其中Controller、Directive是最為重要的。
在我的項(xiàng)目里,使用最多是Directive、Controller,了解這兩個(gè)元件我覺得就差不多了,其他用到時(shí)再查就行。
1. Module
作為模塊組織者,包含其他AngularJS元件。
2. Controller
負(fù)責(zé)跟View溝通, 不處理任何跟DOM有關(guān)的工作
PS:當(dāng)你的Controller里面寫了DOM操作時(shí),就應(yīng)該反省代碼是否寫得有問題了。
3. Directive
類似于HTML標(biāo)簽,可以定義標(biāo)簽的行為,所有與DOM相關(guān)的操作都應(yīng)該寫在這里。
PS:盡量不用DOM操作,但可能還是會(huì)需要用到,用到時(shí)就要在Directive里用。
4. Service
寫可以獨(dú)立運(yùn)作的代碼(與View無關(guān)),共用于元件(例如控制器)之間,不應(yīng)該處理任何跟DOM有關(guān)的工作。
5. Filter
對(duì)數(shù)據(jù)做一些修理,不應(yīng)該處理任何跟DOM有關(guān)的工作。
6. Config
用來定義路由規(guī)則,不應(yīng)該處理任何跟DOM有關(guān)的工作。
上面是一些教程結(jié)合我自己的總結(jié),最常強(qiáng)調(diào)注意一點(diǎn)是對(duì)DOM操作的地方。對(duì)于這些元件我沒有舉例子,貼代碼沒什么意思,如果想學(xué)習(xí)的,還是要自己去實(shí)踐。
雙向數(shù)據(jù)綁定
雙向數(shù)據(jù)綁定是個(gè)重要的特性,值得我們搞明白他的原理。當(dāng)View中有數(shù)據(jù)發(fā)生了變化,這個(gè)變化會(huì)反饋到Model的scope的數(shù)據(jù)上,而當(dāng)scope數(shù)據(jù)發(fā)生變化時(shí),View中的數(shù)據(jù)也會(huì)更新到最新的值。
三個(gè)方法
在說明原理前,有三個(gè)scope重要的方法需要解釋,分別是$apply、$digest、$watch。
1. $watch
注冊(cè)一個(gè)watcher,監(jiān)聽scope的數(shù)據(jù),當(dāng)數(shù)據(jù)變化時(shí)候調(diào)用回調(diào)函數(shù)。第一個(gè)參數(shù)是被監(jiān)聽的數(shù)據(jù),第二個(gè)參數(shù)是回調(diào)函數(shù)。
$scope.$watch('xxx', function(newValue, oldValue) { //update the DOM with newValue});
2. $digest
檢查scope中的數(shù)據(jù)是否發(fā)生了變化,如果變化則關(guān)聯(lián)到該watcher的回調(diào)函數(shù)就會(huì)被執(zhí)行。
3. $apply
這方法是調(diào)用$rootScope.$digest(),在$rootScope開始$digest,隨后會(huì)訪問到所有的children scope中的watchers。$apply()方法有兩種形式。第一種會(huì)接受一個(gè)function作為參數(shù),執(zhí)行該function并且觸發(fā)一輪$digest循環(huán)。第二種會(huì)不接受任何參數(shù),只是觸發(fā)一輪$digest循環(huán)。
PS:AngularJS并不直接調(diào)用$digest(),而是調(diào)用$scope.$apply()
原理
當(dāng)在HTML寫下表達(dá)式如{{name}}或ng-model="name"時(shí),AngularJS在幕后會(huì)為你在scope模型上設(shè)置一個(gè)watcher,如下:
$scope.$watch('name', function(newValue, oldValue) { //update the DOM with newValue});
當(dāng)頁(yè)面JS事件觸發(fā)時(shí),AngularJS會(huì)監(jiān)視到并更改scope數(shù)據(jù),并自動(dòng)觸發(fā)一輪$digest循環(huán),每個(gè)關(guān)聯(lián)的watcher的回調(diào)函數(shù)被執(zhí)行,最后View被更新。
注意地方
1. 有的時(shí)候你發(fā)現(xiàn)明明scope的數(shù)據(jù)已經(jīng)改了,但你發(fā)現(xiàn)View并沒有更新。
這是因?yàn)槟憧赡茉趕etTimeout、異步請(qǐng)求等里去修改數(shù)據(jù),但此時(shí)AngularJS并不知道數(shù)據(jù)已經(jīng)變了,不會(huì)幫你調(diào)用digest循環(huán),所以你需要手動(dòng)調(diào)用$apply。目前一些指令(例ng-click、ng-model)以及服務(wù)(例$timeout、$http)被調(diào)用時(shí)會(huì)自動(dòng)觸發(fā)一次$digest循環(huán),這些就不用手動(dòng)調(diào)$apply。
setTimeout(function() { $scope.$apply(function() { //wrapped this within $apply $scope.name= 'lu'; }); }, 2000);
或
setTimeout(function() { $scope.name= 'lu'; $scope.$apply(); }, 2000);
2. 臟檢查(Dirty Checking)
當(dāng)一個(gè)$digest循環(huán)運(yùn)行時(shí),watchers會(huì)被執(zhí)行來檢查scope中的models是否發(fā)生了變化。如果發(fā)生了變化,那么相應(yīng)的listener函數(shù)就會(huì)被執(zhí)行。在當(dāng)前的一次循環(huán)結(jié)束后,它會(huì)再執(zhí)行一次循環(huán)用來檢查是否有models發(fā)生了變化。這就是臟檢查(Dirty Checking),它用來處理在listener函數(shù)被執(zhí)行時(shí)可能引起的model變化。因此,$digest循環(huán)會(huì)持續(xù)運(yùn)行直到model不再發(fā)生變化,或者$digest循環(huán)的次數(shù)達(dá)到了10次。(這段解析來自其他文章)
PS:$digest循環(huán)最少也會(huì)運(yùn)行兩次,即使在listener函數(shù)中并沒有改變?nèi)魏蝝odel
3. 監(jiān)控的表達(dá)式不要過于復(fù)雜,表達(dá)式數(shù)量不要太多
4. 監(jiān)聽函數(shù)內(nèi)不要有DOM操作,那樣會(huì)顯著降低性能
5. 不能互相監(jiān)聽對(duì)方會(huì)修改的屬性,以免形成交叉引用
總結(jié)
這篇文章我一直在說雙向數(shù)據(jù)綁定的東西,而那些依賴注入、路由、Service等我并沒涉及,是因?yàn)槲矣X得前者是最重要的,能講明白這一點(diǎn)已經(jīng)夠了。