天天看點

AngularJS 自定義控件

angularjs custom directives

好讨厭不帶日期的部落格,而且說得好啰嗦

自定義指令介紹

angularjs 指令作用是在 angulajs 應用中操作 html 渲染。比如說,内插指令 ( {{ }} ), ng-repeat 指令以及 ng-if 指令。

當然你也可以實作自己的。這就是 angularjs 所謂的"教會 html 玩新姿勢"。本文将告訴你如何做到。

指令類型

可以自定義的指令類型如下:

元素

屬性

css class

comment directives

這裡面,angularjs 強烈建議你用元素和屬性類型,而不用 css class 和 comment directives (除非迫不得已)。

指令類型決定了指令何時被激活。當 angularjs 在 html 模闆中找到一個 html 元素的時候,元素指令被激活。當 angularjs 找到一個 html 元素屬性時,屬性指令被激活。當 angularjs 找到一個 css class 時, css class 指令被激活,最後,當 angularjs 找到 html comment 時,comment directive 被激活。

基礎例子

你可以向子產品注冊一個指令,像這樣:

來看子產品中調用的 directive() 函數。當你調用該函數時,意味着你要注冊一個新指令。directive() 函數的第一個參數是新注冊指令的名稱。這是之後你在 html 模闆中調用它的時候用的名稱。例子中,我用了 'div' ,意思是說當 html 模闆每次在找到 html 元素類型是 div 的時候,這個指令都會被激活。

傳遞給 directive 函數的第二個參數是一個工廠函數。調用該函數會傳回一個指令的定義。 angularjs 通過調用該函數來擷取包含指令定義的 javascript 對象。如果你有仔細看上面的例子,你會知道它傳回的确是是一個 javascript 對象。

這個從工廠函數中傳回的 javascript 對象有兩個屬性: restrict 和 template 字段。

restrict 字段用來設定指令何時被激活,是比對到 html 元素時,還是比對到元素屬性時。也就是指令類型。把restrict 設定為 e 時,隻有名為 div 的 html 元素才會激活該指令。把 restrict 設定為 a 時,隻有名為 div 的 html 元素屬性才會激活該指令。你也可以用 ae ,這樣會使得比對到元素名和元素屬性名時,都可以激活該指令。

template 字段是一個 html 模闆,用來替換比對的 div 元素。它會把比對到的 div 當成一個占位符,然後用 html 模闆在同一位置來替換掉它。也就是說,html 模闆替換比對的到 html 元素。

比如說你的 html 頁面有這樣一段 html:

當 angularjs 找到内嵌的 div 的時候,會激活自定義的指令。然後把該 div 元素替換掉,替換後的 html 将變成這樣:

然後你看到了,這段 html 裡面包含了一個内插指令 ({{texttoinsert}})。angularjs 會再執行一次,讓内插指令實際值顯示出來。然後 $scope.texttoinsert 屬性将會在這個 html 點上替換掉内插指令占位符。

template 和 templateurl 屬性

建立自定義指令最簡單的例子就是上面這樣了。你的指令用來生成 html,然後你把 html 放到指令定義對象的 template 屬性中。下面這個例子是上面那最簡單的例子的重複,注意 template 部分:

如果 html 模闆越來越大,把它寫在一個 javascript 字元串中肯定非常難維護。你可以把它放到一個單獨的檔案中,然後 angularjs 可以通過這個檔案把它加載進來。然後再把 html 模闆檔案的 url 放到指令定義對象的 templateurl 屬性中。下面是例子:

然後 angularjs 會從 templateurl 屬性中設定的 url 将 html 模闆加載進來。

用獨立的 html 模闆檔案,設定 templateurl 屬性,在你要建立更多的通用指令時會顯得更加有用,比如說用來顯示使用者資訊的指令。例子:

例子建立了一個指令,當angularjs 找到一個 元素的時候就會激活它。angularjs 加載指向 /myapp/html-templates/userinfo-template.html 的模闆并解析它,它就像從一開始就被嵌在上一級 html 檔案中一樣。

從指令中隔離 $scope

在上面的例子中,把 userinfo 指令硬綁定到了 $scope ,因為 html 模闆是直接引用 texttoinsert 屬性的。直接引用 $scope 讓指令在同一個 controller 中的時候,非常難複用,因為 $scope 在同一個 controller 中的值都是一樣的。比如說,你在頁面的 html 中這樣寫的時候:

這兩個 元素會被同樣的 html 模闆取代,然後綁定到同樣的 $scope 變量上。結果就是兩個 元素将會被一模一樣的 html 代碼給替換了。

為了把兩個 元素綁定到 $scope 中的不同的值,你需要給 html 模闆一個 isolate scope。

所謂 isolate scope 是綁定在指令上的獨立的 scope 對象。下面是定義的例子:

請看 html 模闆中的兩個内插指令 {{user.firstname}} 和 {{user.lastname}}。注意 user. 部分。以及directive.scope 屬性。 directive.scope 是個帶 user 屬性的 javascript 對象。于是 directive.scope 就成為了 isolate scope 對象,現在 html 模闆被綁到了 directive.scope.user 上(通過 {{user.firstname}} 和 {{user.lastname}} 内插指令)。

directive.scope.user 被設定為 "=user" 。意思是說 directive.scope.user 和 scope 中的屬性綁在一起的(不是 isolate scope),scope 中的屬性通過 user 屬性傳入 元素。聽起來挺費勁的,直接看例子:

這兩個 元素都有 user 屬性。user 的值指向了 $scope 中同名屬性,被指定的 $scope 中的屬性将在 userinfo 的 isolate scope object 中被使用。

下面是完整的例子:

compile() 和 link() 函數

如果你需要在你的指令中做更進階的操作,單純使用 html 模闆做不到的時候,你可以考慮使用 compile() 和 link() 函數。

compile() 和 link() 函數定義了指令如何修改比對到的 html。

當指令第一次被 angularjs 編譯的時候 (在 html 中第一次被發現),compile() 函數被調用。compile() 函數将為該元素做一次性配置。

然後 compile() 函數以傳回 link() 作為終結。link() 函數将在每次元素被綁到 $scope 資料時,都被調用。

下面是例子:

this is a transcluded directive {{firstname}}

"

繼續閱讀