![]() |
圖片來源:http://ppt.cc/JVPxN |
但往往找到的程式沒辦法100%完全符合我們的需求
AngularJs提供了一個特別的功能,叫做directive
directive是用來做什麼的呢?
可以自定html的內容與行為,做出來就像是一個客制化的套件
它能夠「簡化重複的code,也能減少DOM操作」。
舉例:
像是台灣的地址包含「郵遞區號」與「地址」兩個
通常我們遇到這種我們都要做兩個input來處理這件事
但同時我們又希望這兩個input的值是同一個輸出(output)
這時我們可以利用directive來處理!
Live Demo如下
directive要怎麼開始?
使用上,他的使用方法跟上一篇講到的ngMessage有點像不過因為我們是客制化的方法(官方提供directive使用方法不同,請見上一篇ngMessage)
所以我們是直接掛在ng-app底下,如下圖

directive分為四種限制(restrict)
- A:作為Html屬性(attribute)【常用】
- 用法:自訂directive為abc是屬性,restrict: 'A'
- E:作為Html元素(element)【常用】
- 用法:自訂directive為abc是元素
,restrict: 'E' - C:作為Html類別(class)【常用】
- 用法:自訂directive為abc是類別
,restrict: 'C' - M:作為Html註解(comment)【非常之少少少少用】
- 用法:自訂directive為abc是註解,restrict: 'M'
以上四種限制可以複合使用,像是 restrice: 'AEC'
如此一來,這個directive就可以接受A、E、C這三種限制(都可以使用)
這邊我做了一個簡單的Demo,讓大家可以輕鬆理解四種限制
為什麼directive名字不一樣!?
在Demo中,大家應該會發現我在directive的命名是「myDirective」,但使用卻變成「my-directive」
其實這個現象在ngMessage的時候也有發生過唷!
這其實是ng對於命名上的一個正規化(Normalization)
我們以「myDirective」為例子,以下五種都是可以對應的名稱!
- my-directive
- my_directive
- my:directive
- data-my-directive
- x-my-directive
*貼心小連結>陸。表單驗證
template是什麼?是directive的一部份嗎?
template是directive的設定屬性(options)之一,就像是一台電腦,使用前需要把設定都設定(settings)完成,就可以照著你的想法或習慣去使用了!
那麼,directive的設定屬性(options)有哪些呢?
restrict【常用】
>型別:字串(string),預設為A,包含AECM四種可混搭。
這個屬性剛剛有解釋過,用以宣告directive的用法。
priority
>型別:數字(int)
如果同一個元素底下掛有不只一個的directive,那麼就會依照這個屬性來判斷優先順序。
template【常用】
>型別:字串(string)
使用「字串」來編輯Html內容,套用此directive的元素會被代換為這邊的Html。
ex:template: '<div>這是Directive!</div>'
ex:template: '<div>這是Directive!</div>'
*上方的demo就是利用template來呈現的!
templateUrl
>型別:字串(string)
用法類似template,但不同的是,templateUrl是用「字串」編輯檔案名稱。
ex:templateUrl: 'index.html'
replace【常用】
>型別:布林值(bool),預設為false。
如果內容設定為True,會把掛directive的元素取代掉;反之,會插入元素當中。
transclude
>型別:布林值(bool),預設為false,需搭配templdate一起使用。
可把要把掛有directive的元素「內容」插入directive的template中任意的位置!
ex:若transclude為true, templdate: '<div>這是Directive!</div><div ng-transclude></div>',其中ng-transclude就是ng提供設定「原本的元素內容」的方法。
*這也解釋了上方directive為什麼裡面的內容沒有顯示的原因!scope【超級好用!】
>型別:物件(object)或是布林值(bool),預設為false。
四種情況會造成不同的結果,如下:
四種情況會造成不同的結果,如下:
- true:則在directive中建立一個獨立的scope,並且「繼承」上層的scope,而此scope可以在directive中使用。
- false:則「共用」上層的scope,不會產生獨立scope。
- {}:產生一個獨立的scope,不受上層scope影響。
- {= or @}:指定要與上層scope關連的屬性(需要指定掛在directive元素上的屬性),用「=」表示雙向綁定,會互相影響;用「@」表示單向綁定,用法如:{ name : '=' }
這邊我也做了一個Demo,讓大家可以釐清觀念!
controller
>型別:函數(function),預設沒有。
定義directive的controller,用於directive之間分享資訊,否則請使用link function。
這個概念有點抽象,我利用一開始的「台灣地址」Demo來改寫使用controller
讓大家可以對於controller更有概念!
這個概念有點抽象,我利用一開始的「台灣地址」Demo來改寫使用controller
讓大家可以對於controller更有概念!
require【常用】
>型別:字串陣列(string array)
檢查必要的屬性,否則會出錯,
ex:require: ['ngModel'] 表示此directive所掛的元素需掛有ng-model!
另外可以在前面加上前置符號(prefix),各有意義不同:
- ?:就算找不到也不要出錯,使其檢查通過。ex:require: ['?ngModel']
- ^:檢查掛directive的元素與父元素的屬性存在。ex:require: ['^ngModel']
- ^^:只檢查父元素屬性存在。ex:require: ['^^ngModel']
link【常用】
>型別:函數(function)
會被保留並在程式中重複利用,可以在此註冊監聽事件、初始化內容、與DOM元素的設定。
- 使用時機:針對特定元素註冊事件,而且可能會用到scope。
- 用法:link: function(scope, elem, attrs){ //doing things here. }
其中function有三個參數可以用scope是這個directive的scope(若false就是上層的scope);elem代表這個掛著directive的元素;attr代表此元素的屬性。
這邊我也做一個Demo,讓大家稍微了解一下link function!
Demo程式中用到了「$scope.$apply()」的方法
用意是「執行」$apply()中的方法!
通常比較少用到這個方法,因為大部分的事件(包含ngClick、controller init或是$http的事件)都已經被ng包上$apply(),而且在$apply()中是不能重複呼叫$apply()的(會出error),所以通常使用到的情況都是瀏覽器DOM事件、setTimeout、XHR(XML Http Request) 或是第三方套件(3-Party Libraries)。
這邊我也做一個Demo,讓大家稍微了解一下link function!
Demo程式中用到了「$scope.$apply()」的方法
用意是「執行」$apply()中的方法!
通常比較少用到這個方法,因為大部分的事件(包含ngClick、controller init或是$http的事件)都已經被ng包上$apply(),而且在$apply()中是不能重複呼叫$apply()的(會出error),所以通常使用到的情況都是瀏覽器DOM事件、setTimeout、XHR(XML Http Request) 或是第三方套件(3-Party Libraries)。
compile
>型別:函數(function)
通常你只會用到link function就能解決問題,而compile function並不像link是可以重複利用的,只會再程式一開始執行。
- 使用時機:在DOM在畫面上出現(渲染render)前,將其改變,且沒有scope。
- 特點:return為函數(function)此特點讓同樣的directive可以共用方法。
- 用法:compile: function(tElement, tAttrs) { //doing things here. }
其中tElement跟tAttrs參數跟link function的參數意義相同,指的都是元素與元素的屬性。
這邊我也做了一個Demo,讓大家了解一下compile function!
Demo程式中用到了element.append()的方法
這是JavaScript的用法,把元素(字串型態)插入該元素底下。
Demo程式中也用到了上方說過的transclude的概念,來重複利用directive元素下的子元素!
(欸!
- 用template置換html
- 用replace選擇是否要取代元素
- 用require限制必須要有的屬性
- 用scope可以靈活的運用
- 用link去綁定要綁定的事件
directive可以做的事情很多,需要用的東西也很多,在做directive前,務必請先想想做了這個directive是否可以重複利用,否則做了一個directive只用了一次,或是只有特定的情境可以使用,其實也很可惜對吧?
這邊我也做了一個Demo,讓大家了解一下compile function!
Demo程式中用到了element.append()的方法
這是JavaScript的用法,把元素(字串型態)插入該元素底下。
Demo程式中也用到了上方說過的transclude的概念,來重複利用directive元素下的子元素!
後記
AngualrJs的directive講到這裡,其實講的不多,因為directive包山包海,能做的事情太多,所以要講的東西也很多,所以本篇用了很多demo程式來解釋文章,讓大家可以在看文章的時候離現實情況更貼近一點,當然directive能做的事情還很多,就有待大家去尋找大祕寶了重點複習
directive有AECM四種restrict,可以很自由的自訂directive宣告的方法!- 用template置換html
- 用replace選擇是否要取代元素
- 用require限制必須要有的屬性
- 用scope可以靈活的運用
- 用link去綁定要綁定的事件
directive可以做的事情很多,需要用的東西也很多,在做directive前,務必請先想想做了這個directive是否可以重複利用,否則做了一個directive只用了一次,或是只有特定的情境可以使用,其實也很可惜對吧?
下集預告
下一篇,也會是這個ng初階教學的最後一篇,技術部分討論到這邊其實已經差不多了,下一篇會以開發者的經驗來談談ng的經驗談,敬請期待囉!
那麼,我們下次見囉!