Angularjs 開發指南 自定義指令(custom directives)

使用Angularjs開發,很重要的一步是須要開發自定義的指令(custom directives)。
接下來分幾個步驟記錄如何開發一個自定義的指令。javascript

目錄:

  1. 指令是什麼?html

  2. 寫一個基本的指令java

  3. 指令的屬性說明node

指令是什麼

Angularjs中的指令,我我的的簡單的理解:指令=控件
指令實際是對Html元素的擴展,傳統的服務端控件,例如asp.net中的服務器端控件(處理在服務端,最終編譯成html返回給客戶端),其實也是對Html元素的擴展。angularjs中的指令,最終其實也是通過angularjs(其實就是javascript)的編譯處理,最終輸出成html。具體的細節不繼續細說,若是對angularjs毫無認識的童鞋,建議瞭解一些基本概念之後再看。angularjs

寫一個基本的指令

var simpleapp=angular.module('simpleapp');
simpleapp.directive('simpleDirective', function () {
    var directiveObj = {
        template:'<p>這是一個自定義指令</p>'
    }
    return directiveObj;
});
<body ng-app="simpleapp">
    <div ng-controller="app">
        <div simple-directive></div>
    </div>
</body>

以上就是一個簡單的自定義指令,最終頁面會輸出指令裏包含的內容。這裏先不說屬性,只先討論應該在何處定義,下一節再說如何定義指令內部。瀏覽器

看上面示例,能夠知道指令必須是在module下的,先得獲取到模塊對象simpleapp,而後使用directive函數來定義一個指令。安全

指令屬性

在上節例子中能夠看到,simpleapp.directive第二個參數最終執行後須要返回一個對象(我叫它指令對象),這個指令對象裏面有能夠包含不少屬性,大概有12個,這節主要解釋這些屬性的用法。
我主要是按功能來給這些屬性分類並講解。服務器

template和templateUrl都是用來指定指令模板的,模板是用來編譯內容的一個基本模型。app

template

字符串或函數,能夠指定爲一個html字符串,也能夠是一個特定的函數。
例子:asp.net

template: '<div></div>'
//or
template:function(tElement, tAttrs) { return "..." },

當爲一個函數時,函數應該返回一個字符串。函數的tElement, tAttrs分別表明一個元素和元素對應的屬性集合。

templateUrl

字符串或函數,能夠指定一個模板的地址,也能夠是一個特定的函數。

templateUrl: 'sometemplate.html'
//or
templateUrl:function(tElement, tAttrs) { return tAttrs.xx+"xx.html" },

當爲一個函數時,函數應該返回一個字符串。函數的tElement, tAttrs分別表明一個元素和元素對應的屬性集合。

restrict

字符串,這個屬性用來限制指令匹配模式,能夠有四種模式,分別是A(Attribute)、E(Element)、C(Class)、M(註釋),這四種模式能夠自由組合。

<!--屬性模式,默認匹配-->
        <div simple-directive></div>
        
        <!--元素模式,默認匹配-->
        <simple-directive></simple-directive>
        
        <!--樣式模式-->
        <div class="simple-directive"></div>
        
        <!--註釋模式,主要兩側須要空格-->
        <!-- directive:simple-directive -->
        <div class="simple-directive"></div>

須要注意的是,若是不設置此屬性,則默認匹配EA兩種模式。

疑問:M的匹配方式是靠C控制的,即若是設置restrict:'C',實際匹配的是C和M,若是單獨設置restrict:'M'則沒法生效。--這個問題不知道是爲何?

templateNamespace

主要是標記文檔類型,可設置爲html、svg、math。具體使用場景我也不曾使用過。
此處貼上官方說明:

* String representing the document type used by the markup in the template.
 * AngularJS needs this information as those elements need to be created and cloned
 * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
 *
 * * `html` - All root nodes in the template are HTML. Root nodes may also be
 *   top-level elements such as `<svg>` or `<math>`.
 * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
 * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
 *
 * If no `templateNamespace` is specified, then the namespace is considered to be `html`.

priority

優先級,當一個DOM上有多個指令時,有會須要指定指令執行的順序。 這個優先級就是用來在執行指令的compile函數前先排序的。高優先級的先執行。 相同優先級的指令順序沒有被指定誰先執行

transclude

我的認爲這個屬性仍是比較難解釋的,自己英文也不知怎麼解釋。我按我的理解叫作」局部替換「,這個屬性一般是要和ng-transclude配合。
先說下官方的意思:

* Extract the contents of the element where the directive appears and make it available to the directive.
 * The contents are compiled and provided to the directive as a **transclusion function**. See the
 * {@link $compile#transclusion Transclusion} section below.
 *
 * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
 * directive's element or the entire element:
 *
 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
 * * `'element'` - transclude the whole of the directive's element including any directives on this
 *   element that defined at a lower priority than this directive. When used, the `template`
 *   property is ignored.

我的理解是transclude開啓時,在編譯完成之後,會將編譯後的內容放到ng-transclude指定的位置中,相似於佔位符的做用。
我仍是寫一個例子,這樣可以更直觀的看出它是什麼意思

//JS
simpleapp.directive('simpleTransclude', function () {
    return {
        template: '<div><div>這是模板原有的內容</div><div ng-transclude></div></div>',
        transclude: true
    };
})

//HTML
<simple-transclude>這是指令內容</simple-transclude>

//瀏覽器最終展示效果
<simple-transclude>
    <div>
        <div>這是模板原有的內容</div>
        <div ng-transclude="">
            <span class="ng-scope">這是指令內容</span>
        </div>
    </div>
</simple-transclude>

scope

做用域,若是聲明瞭,則指令會產生一個私有的做用域,若是有多個,則只有一個新的會被建立,也就是最後一個。對更節點無效。並且這個做用域是孤立的,不會以原型繼承的方式直接繼承自父做用域。這是須要注意的地方。關於scope的內容須要將的太多,放在之後的文章中詳細說(難道說其實我本身也搞不清?)。

controller

控制器的構造對象。這個控制器函數是在預編譯階段被執行的,而且它是共享的,其餘指令能夠經過它的名字獲得(參考依賴屬性[require attribute])。
注意它是在預編譯的時候執行,這一點很是重要,這意味着你能夠在預編譯前,在這個controller中作一些你想作的事情。

controllerAs

AngularJS 1.2版本中提供了Controller As語法,簡單說就是能夠在Controller中使用this來替代$scope。其餘與controller是同樣的。

require

請求將另外一個控制器做爲參數傳入到當前連接函數。 這個請求須要傳遞被請求指令的控制器的名字。若是沒有找到,就會觸發一個錯誤。請求的名字能夠加上下面兩個前綴:

? - 不要觸發錯誤,這只是一個可選的請求。
^ - 沒找到的話,在父元素的controller裏面也查找有沒有。

compile

編譯函數,在時執行,且指執行一次。

function compile(tElement, tAttrs, transclude) { ... }

編譯函數是用來處理須要修改模板DOM的狀況的。由於大部分指令都不須要修改模板,因此這個函數也不經常使用。須要用到的例子有ngTrepeat,這個是須要修改模板的,還有ngView這個是須要異步載入內容的。編譯函數接受如下參數。

tElement - template element - 指令所在的元素。對這個元素及其子元素進行變形之類的操做是安全的。

tAttrs - template attributes - 這個元素上全部指令聲明的屬性,這些屬性都是在編譯函數裏共享的, 參考章節「屬性」。

transclude - 一個嵌入的連接函數function(scope, cloneLinkingFn)。

注意:若是模板被克隆了,那麼模版實例和連接實例可能不是同一個對象。 因此在編譯函數不要進行任何DOM變形以外的操做。 更重要的,DOM監聽事件的註冊應該在連接函數中作,而不是編譯函數中。

編譯函數能夠返回一個對象或者函數。

返回函數 - 等效於在編譯函數不存在時,使用配置對象的link屬性註冊的連接函數。

返回對象 - 返回一個經過pre或post屬性註冊了函數的對象- 使你能更具體的連接函數的執行點。參考下面pre-linking和post-liking函數的解釋。

link

連接函數

function link(scope, iElement, iAttrs, controller) { ... }

連接函數負責註冊DOM事件和更新DOM。它是在模板被克隆以後執行的。 它也是大部分指令邏輯代碼編寫的地方。

scope - 指令須要監聽的做用域。

iElement - instance element - 指令所在的元素。只有在postLink函數中對元素的子元素進行操做纔是安全的,由於那時它們才已經所有鏈接好。

iAttrs - instance attributes - 實例屬性,一個標準化的、全部聲明在當前元素上的屬性列表,這些屬性在全部連接函數間是共享的。參考「屬性」。

controller - 控制器實例,若是至少有一個指令定義了控制器,那麼這個控制器就會被傳遞。控制器也是指令間共享的,指令能夠用它來相互通訊。

Pre-linking function 在子元素被連接前執行。不能用來進行DOM的變形,覺得可能致使連接函數找不到正確的元素來連接。

Post-linking function 全部元素都被連接後執行。能夠操做DOM的變形。

說明

link和compile是指令的關鍵部分,留在下一章中詳細討論。

相關文章
相關標籤/搜索