AngularJS的啟動引導過程


原文:http://www.angularjs.cn/A137?utm_source=ourjs.com

目錄:

  1. 引導之前
  2. 自動引導啟動框架
  3. 手工引導啟動框架
  4. 引導第1步:創建注入器
  5. 引導第2步:創建根作用域
  6. 引導第3步:編譯DOM子樹
  7. 編譯器/$compile
  8. 指令/directive
  9. 指令的規范化

1.引導之前:庫階段

在示例中,我們定義了一個指令ez-duang, 它應該會展開成一個動畫 顯示出來。 AngularJS代碼:

 angular.module("ezstuff",[]) .directive("ezDuang",function(){ return { restrict : "E", template : "<img src='http://ww4.sinaimg.cn/bmiddle/757eb2ffjw1eptcr4qobjg209205dthh.gif'>" }; });

html代碼:

  • 應該在下面看到一幅動畫才對!

但是,看起來沒有什么動畫顯示出來。AngularJS似乎沒有工作,為什么?

有點像操作系統,AngularJs也有一個啟動引導的概念。

當你在HTML文件中引入angular.min.js時,AngularJS只是建立了一個全局的 angular對象,這個對象有一些方法可供開發者調用,但應用的框架還沒有建立。

在這個階段,AngularJS還只是一個庫,和jQuery類似,你可以使用angular.element() 操作DOM,也可以使用angular.injector()創建注入器... 但是,你定義的指令,你 創建的控制器,你封裝的服務,你開發的模板...所有這些組件,還靜靜地躺在那里, 沒有被整合在一起。

我們說,框架還沒有運轉起來,現在還是庫階段。

只有通過啟動引導,AngularJS框架才開始將那些組件拼接在一起,應用才真正 開始運轉。

像下面這樣,試着給html元素增加一個ng-app指令,再重新運行!

 <html ng-app="ezstuff"> .... </html>

2.自動引導啟動框架

就像你看到的那樣,如果HTML模板中有某個標簽有ng-app屬性,那么當DOM樹建立成功后, AngularJS就會自動進入引導過程,啟動整個框架:

111.png

試着把ng-app指令挪到body元素上,看看有什么不同?

3.手工引導啟動框架

在大多數情況下,我們都使用ng-app指令來進行自動引導啟動,但是如果一個HTML文件中 有多個ng-app,AngularJS只會自動引導啟動它找到的第一個ng-app應用,這是需要手工引導 的一個應用場景。

我們可以利用 angular.bootstrap() 方法進行手動引導:

angular.bootstrap(element, [modules], [config]);

bootstrap方法有三個參數:

element : 一個DOM元素,以這個元素為Angular應用的根,等同自動引導時ng-app所在 的元素。這個參數是必須的。比如:document、document.body等。 modules : 引導時需要載入的模塊數組。比如:[]、["ezstuff"]等。由於我們的HTML中引用 了ezstuff模塊中定義的ez-duang指令,所以,我們需要指定載入ezstuff模塊。 config :引導配置項,可選。我們先忽略。 最終,我們使用如下的形式進行手動引導:

angular.bootstrap(document,["ezstuff"]); 請點擊【手動引導】按鈕啟動引導過程!

4.引導第1步:創建注入器

引導過程使AngularJS從庫轉變成了一個框架。

回憶我們之前提到,AngularJS深入骨髓地使用着依賴注入,那么,在引導過程 之初,首先需要創建一個注入器就毫不奇怪了。

注入器是通向AngularJS所有功能的入口,而AngularJS的功能實現,是通過模塊的方式組織的。所以, 在創建注入器的時候,需要告訴AngularJS載入哪些模塊(ng模塊是內置載入的,不需要顯式指定)。

0022.png

在自動啟動引導的場景下,可以給ng-app賦值以指定一個需要載入的模塊,比如: ng-app = "ezstuff"

在手動啟動引導的場景下,通過bootstrap方法的第二個參數指定需要載入的模塊,比如: angular.bootstrap(document,["ezstuff"]);

INSIDE:無論自動啟動還是手工啟動,最終都是調用angular對象上的injector()方法創建了一個 注入器,然后把這個注入器存入了根對象的data里: var injector = angular.injector(["ng","ezstuff"]); angular.element(document).data("$injector",injector);

我們在開始模擬引導啟動過程的第一步:創建注入器。

5.引導第2步:創建根作用域

scope對象是AngularJS實現數據綁定的重要服務,所以,在引導啟動建立了注入器之后, AngularJS馬上在應用的根節點上創建一個根作用域:$rootScope對象。

0033.png

如果是自動引導啟動,那么ng-app所在的DOM節點對應着根作用域。如果是手工引導啟動, 那么在bootstrap方法中指定的第一個參數就對應着根作用域。

無論哪一種情況,一旦$rootScope對象創建成功,AngularJS就將這個對象存儲到根節點 的data中,我們可以使用如下的方法查看這個對象: angular.element(approot).data("$rootScope");

你可以擺弄一下代碼,看看$rootScope到底是什么東西。

6.引導第3步:編譯DOM子樹

引導過程的最后一步,是以ng-app所在DOM節點為根節點,對這棵DOM子樹進行編譯。

0044.png

編譯過程通常借助於指令,完成這幾種操作:

  1. 對DOM對象進行變換。
  2. 在DOM對象上掛接事件監聽。
  3. 在DOM對象對應的scope對象上掛接數據監聽。 編譯過程是AngularJS相當有特點的一個存在,我們將在下一節繼續深入。

現在你應該看到結果了吧?

7.編譯器/$compile

編譯器$compile是一個AngularJS的內置服務,它負責遍歷DOM樹來查找匹配指令, 並調用指令的實現代碼進行處理。

HTML編譯包括3個步驟:

匹配指令 $compile遍歷DOM樹,如果發現有元素匹配了某個指令,那么這個指令將被加入 該DOM元素的指令列表中。一個DOM元素可能匹配多個指令。

執行指令的編譯函數 當一個DOM元素的所有指令都找齊后,編譯器根據指令的優先級/priority指令進行排序。 每個指令的compile函數被依次執行。每個compile執行的結果產生一個link函數,這些 link函數合並成一個復合link函數。

執行生成的鏈接函數 $compile通過執行指令的link函數,將模板和scope鏈接起來。結果就是一個DOM視圖和scope對象模型 之間的動態數據綁定。

為何將編譯和連接兩個步驟分開?

簡單說,當數據模型的變化會導致DOM結構變化時,指令就需要分別定義compile()函數和link函數。 例如,ng-repeat指令需要為數據集合中的每個成員復制DOM元素。將編譯和鏈接過程分開可以有效 地提高性能,因為DOM的復制放在compile()里,僅需要執行一次,但鏈接則發生在每個生成的DOM元素 上,所以指令的link()函數會執行多次。

指令很少需要compile函數,因為大多數指令考慮的是作用於特定的DOM元素實例,而不是改變DOM 的結構。所以link函數更常用。

8.指令/directive

籠統地說,指令是DOM元素(例如屬性、元素、CSS類等)上的標記符,用來告訴AngularJS的HTML編譯器 ($compile服務)將特定的行為綁定到DOM元素,或者改變DOM元素。

指令可以放置在元素名、屬性、CSS類名稱及備注中。下面是一些等效的觸發"ng-bind"指令的寫法:

 <span ng-bind="exp"></span> <span class="ng-bind: exp;"></span> <ng-bind></ng-bind> <!-- directive: ng-bind exp -->

指令的實現本質上就是一個類工廠,它返回一個指令定義對象,編譯器根據這個指令定義對象進行操作。

0055.png

問題是,HTML中的ez-duang,怎么就匹配到了JavaScript中的ezDuang?

9.指令的規范化

AngularJS在進行匹配檢測之前,首先對HTML元素的標簽和屬性名轉化成規范的駝峰式字符串:

  1. 去除名稱前綴的x-和data-
  2. 以: , - 或 _ 為分割符,將字符串切分成單詞,除第一個單詞外,其余單詞首字母大寫
  3. 重新拼接各單詞 例如,下面的寫法都等效地匹配ngBind指令:

     <span ng-bind="name"></span> <br> <span ng:bind="name"></span> <br> <span ng_bind="name"></span> <br> <span data-ng-bind="name"></span> <br> <span x-ng-bind="name"></span> <br>

所以,在前面的課程中,我們在HTML中使用的ez-duang指令,將被規范為ezDuang, 編譯器使用這個規范化的名稱與注冊的指令進行匹配。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM