1.指令是什么
第一:指令就是DOM元素的標記(如屬性、元素名、注釋或CSS類名)
第二:讓編譯器(compiler)給dom元素附加指定的行為或轉換(DOM元素的crud)
angular有許多內置的指令,ngbind,ngModel,ngClass,很像控制器和服務,你也可以創建自己的。
當angular引導你的程序的時候,Compiler會遍歷DOM樹去匹配指令并將指令的功能附加到DOM元素。
編譯語言:
c,C++這些編譯代碼為匯編或二進制代碼的語言。
2.匹配指令
在我們寫指令前我們首先要知道angular的compiler怎么決定何時使用指定的指令。
和元素選擇器很類似,當指令是他聲明的一部分,我們可以說一個元素匹配一個指令。
下邊這些都匹配了ng-model
<input ng-model="foo">
<input data-ng-model="foo">
下邊的指令匹配 person
<person>{{name}}</person>
3.指令名稱的規范化
angular規范了標簽和屬性名,通過這些,決定了哪個元素匹配了哪個指令。
一般通過區分大小寫的駝峰命名法來引用指令。然而,因為HTML是不區分大小寫的,
我們在DOM中引用指令通過小寫的格式,一般在DOM元素上用橫線分割。(ng-model)。
規范化的過程:
- 抽掉 x- 和 data- 從元素或屬性前面
- 用“:”,“-”或“_”方法替代駝峰命名法
下邊例子中ngbind的命名的是等價的
<div ng-controller="Controller">
Hello <input ng-model='name'> <hr/>
<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/>
</div>
建議使用'ng-bind',若使用HTML驗證工具建議用'data-ng-bind'的形式。其他的形式是歷史遺留問題。
4.指令類型
編譯器可以基于元素名、屬性、類名和注釋來匹配指令。
下面是MyDir的四種方法:
<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>
一般推薦使用標簽名或屬性
5.創建指令
首先看一下怎么注冊指令。和控制器一樣,指令也是注冊在modules上面。
使用module.directive創建指令。
directive接受兩個參數:
第一個是規范化的指令名稱;
第二個是factory方法。
這個工廠方法返回一個對象,這個對象上面有很多選項。這些選項告訴了編譯器怎么匹配的元素增加行為。
這個工廠方法只在第一次compiler匹配到的時候調用(inovke)。
你可以在這里面處理一些初始化的方法。這個函數被$injector.invoke調用注入。
最佳實踐:
最好定義一些不容易沖突的指令名。例如,angular的內置變量都以ng開頭。
6.模板擴展指令
如果你有一塊模板表示信息,出現了很多次。并且,當你在一個地方寫改的時候,
其他的地方都需要修改。這種情況用指令可以加大簡化你的代碼。
compiler除了編譯某個指令外,還會編譯指令模板里面的子指令。
最佳實踐:
除了html文件小,最好還是拆分為html模板,用templateUrl去引用。
templateUrl也可以是函數,第一個參數是ele,第二個參數是屬性。
restrict 有四個值:
‘A’,‘E’,‘C’,‘M’。
最佳實踐:
標簽名用在類似 dialog這種指令里。屬性用在類似 drag這樣的指令中。
7.隔離的指令作用域
傳統做法,每個指令都需要在外面包一個controller來提供scope;現在,
我們想要一個內外分離的,外部映射到內部的scope。
我們用 isolate scope來實現這個功能。
我們用scope屬性實現。
isolate scope隔離了除了映射進來的 所有的外部scope。
這樣對構建可重用的組件很有用。
scope是原型繼承的。
想重建可重用的組建的時候,要用scope屬性。
8.創建一個操作DOM的指令
一般通過link這個選項,來讓指令監聽和操作DOM。
link在模板clone后執行,指令的邏輯都放在這里。
link 函數這樣用
function link(scope,element,attrs,controller,transcludeFn) { ... }
scope:
element: 指令匹配的那個jqLite包裹的元素。
attrs: 屬性
controller:
transcludeFn:
directive 和 controller一樣,都可以使用依賴注入。
angular自己可以觸發一些事件。當angular的compiler編譯的元素銷毀的時候,
他就觸發了一個 $destory事件。和scope很類似,當scope銷毀的時候,他就會廣播一個$destory事件。
通過監聽$destory事件,你可以手動刪除一個事件監聽,防止內存泄漏。
當scope和element銷毀的時候,注冊到scope 和 element上面的回調函數可以自動清除。
如果在服務上注冊了一個回調函數,或在沒有刪除DOM節點上注冊一個監聽器,你需要手動清除以防內存泄漏。
9.創建一個包含其他元素的指令
transclude選項改變scope嵌入的方式。指令中的內容直接引用指令外的scope,而不是內部的。
有了它,就可以訪問外部的scope。
transclude屬性對那些包裹隨機內容的指令很有用。因為,只有這樣他才不用處理每一個內嵌內容需要的model。
最佳實踐:
transclude: true,當你創建一個需要包裹隨機內容的指令的時候。
&attr 適合向外映射一個行為,也就是方法。
=attr 映射一個字符串或對象。
通過向外映射方法,向外傳遞數據。
10.創建一個事件監聽指令
通過link來添加事件和操作DOM
11.創建一個交流用途的指令
require
^這個前綴意味著:指令搜尋父元素的控制器。(一個,在自己或父親上面查找控制器。一個也沒有,在自己上面找)
controller選項可以獲取controller。
當一個指令需要控制器的時候,link里面的第四個參數就是這個控制器。
如果require多個控制器,那么第四個參數就是控制器的數據。
link和controller的關系:
controller可以暴露API接口方法。
link函數可以和controller交互,當有require的時候。
最佳實踐:
當你想暴露接口的時候,用controller