建立angular自定義指令
阿新 • • 發佈:2019-01-27
——本文轉自他處,稍作修改,完全為了方便自己理解,如有侵犯,請告知。
指令(Directives)是所有AngularJS應用最重要的部分。儘管AngularJS已經提供了非常豐富的指令,但還是經常需要建立應用特定的指令。
一個Angular指令可以有以下的四種表現形式:
1. 一個新的HTML元素(<data-picker></data-picker>) (A)
2. 元素的屬性(<input type=”text” data-picker/>) (E)
3.
CSS class(<input type=”text” class=”data-picker”/>) (C)
4. 註釋(<!–directive:data-picker –>) (M)
當然,我們可以控制我們的指令在HTML中的表現形式。下面我們來看一下AngularJS中的一個典型的指令的寫法。指令註冊的方式與
controller 一樣,但是它返回的是一個擁有指令配置屬性的簡單物件(指令定義物件) 。
首先,建立一個指令:
通過指令定義的元素屬性(A)和標籤屬性(E)來使用該指令:var app = angular.module('myapp', []); app.directive('helloWorld', function() { return { restrict: 'AE', replace: 'true', template: '<h1>Hello World!!</h1>' }; });
元素屬性使用:
<hello-world/>或<hello:world/>
標籤屬性使用:
<div hello-world></div>或<div hello:world/>
通過上面的例子,我們看到restrict設定為AE,其意如上所說,共有四種定義,分別為A,E,C,M;
還有replace設定為true代表著生成的HTML內容是會替換掉定義此指令的HTML元素,即
如果為false,則預設值,生成的模板會被插入到元素中去;<hello-world/>或<hello:world/>、<div hello-world></div>或<div hello:world/>
還有templat:這個屬性規定了指令被Angular編譯和連結(link)後生成的HTML標記。這個屬性值不一定要是簡單的字串。template 可以非常複雜,而且經常包含其他的指令,以及表示式({{ }})等。更多的情況下你可能會見到 templateUrl, 而不是 template。所以,理想情況下,你應該將模板放到一個特定的HTML檔案中,然後將 templateUrl 屬性指向它。
link和scope
如上模板並沒有太大意義,一般我們會在特定的scope下編譯。預設情況下,指令並不會建立新的子scope。預設情況下它使用父scope。也就是說,如果指令存在於一個controller下,它就會使用這個controller的scope。 如何運用scope,我們要用到一個叫做 link 的函式。它由指令定義物件中的link屬性配置。我們來改變一下我們的 helloWorld 指令,當用戶在一個輸入框中輸入一種顏色的名稱時,Hello World 文字的背景色自動發生變化。同時,當用戶在 Hello World 文字上點選時,背景色變回白色。 相應的HTML標記如下:<body ng-controller="myController">
<input type="text" ng-model="color" />
<hello-world/>
</body>
app.directive('helloWorld', function() {
return {
restrict: 'AE',
replace: true,
template: '<p style="background-color:{{color}}">Hello World',
link: function(scope, elem, attrs) {
elem.bind('click', function() {
elem.css('background-color', 'white');
scope.$apply(function() {
scope.color = "white";
});
});
elem.bind('mouseover', function() {
elem.css('cursor', 'pointer');
});
}
};
});
以上link函式有三個引數:
scope:指令的scope,例子中的scope為父Controller的scope;
elem:指令的DOM。該DOM為jQuery包裝過的,所以可以通過jQuery來操作;
attrs:一個包含了指令所在元素的屬性的標準化的引數物件;(理解的有點模糊)
link函式主要用來為DOM元素新增事件監聽、監視模型屬性變化、以及更新DOM。在上面的指令程式碼片段中,我們添加了兩個事件, click,和 mouseover。click 處理函式用來重置 <p> 的背景色,而 mouseover 處理函式改變滑鼠為 pointer。在模板中有一個表示式 {{color}},當父scope中的 color 發生變化時,它用來改變 Hello World 文字的背景色。compile函式
compile 函式在 link 函式被執行之前用來做一些DOM改造。它接收下面的引數:1、tElement – 指令所在的元素
2、attrs – 元素上賦予的引數的標準化列表 要注意的是 compile 函式不能訪問 scope,並且必須返回一個 link 函式。但是如果沒有設定 compile 函式,你可以正常地配置 link 函式,(有了compile,就不能用link,link函式由compile返回)。compile函式可以寫成如下的形式:
app.directive('myDirective', function() {
return {
compile: function(tElem,attrs) {
return function(scope,elem,attrs) {
};
}
};
});
多數情況下我們只用到link函式,這是因為大部分的指令只需要考慮註冊事件監聽、監視模型、以及更新DOM等,這些都可以在 link
函式中完成。
改變指令的scope
預設情況下,指令獲取它父節點的controller的scope。但這並不適用於所有情況。如果將父controller的scope暴露給指令,那麼他們可以隨意地修改 scope 的屬性。在某些情況下,你的指令希望能夠新增一些僅限內部使用的屬性和方法。如果我們在父的scope中新增,會汙染父scope。 其實我們還有兩種選擇: 1、子scope :這個scope原型繼承子父scope。 2、隔離的scope –:孤立存在不繼承自父scope的scope。這樣的scope可以通過指令定義物件中 scope 屬性來配置:
繼承父scope的子scope:
app.directive('helloWorld', function() {
return {
scope: true,
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
隔離的scope:
app.directive('helloWorld', function() {
return {
scope: {},
restrict: 'AE',
replace: 'true',
template: '<h3>Hello World!!</h3>'
};
});
通過隔離scope,我們可以建立重用的指令非常有好處,我們能夠保證我們的指令是自包含的,可以被很容易的插入到HTML應用中。 它內部不能訪問父的scope,所保證了父scope不被汙染。
隔離scope和父scope之間的資料繫結
隔離指令的scope會帶來很多的便利,尤其是在你要操作多個scope模型的時候。但有時為了使程式碼能夠正確工作,你也需要從指令內部訪問父scope的屬性。選擇一:使用 @ 實現單向文字繫結
在下面的指令定義中,我們指定了隔離scope中的屬性 color 繫結到指令所在HTML元素上的引數 colorAttr。在HTML標記中,你可以看到 {{color}}表示式被指定給了 color-attr 引數。當表示式的值發生改變時,color-attr 引數也跟著改變。隔離scope中的 color 屬性的值也相應地被改變。app.directive('helloWorld', function() {
return {
scope: {
color: '@colorAttr'
},
....
};
});
<body ng-controller="MainCtrl">
<input type="text" ng-model="color" />
<hello-world color-attr="{{color}}"/>
</body>
注意點:當隔離scope屬性和指令元素引數的名字一樣時,我們可以更簡單的方式設定scope繫結:
app.directive('helloWorld', function() {
return {
scope: {
color: '@'
},
....
};
});
<hello-world color="{{color}}"/>
選擇二:使用 = 實現雙向繫結
我們把指令的定義改變成下面的樣子:app.directive('helloWorld', function() {
return {
scope: {
color: '='
},
....
};
});
<body ng-controller="MainCtrl">
<input type="text" ng-model="color" />
<hello-world color="color"/>
</body>
與 @ 不同,這種方式讓你能夠給屬性指定一個真實的scope資料模型,而不是簡單的字串。這樣你就可以傳遞簡單的字串、陣列、甚至複雜的物件給隔離scope。同時,還支援雙向的繫結。每當父scope屬性變化時,相對應的隔離scope中的屬性也跟著改變,反之亦然。和之前的一樣,你也可以監視這個scope屬性的變化。
選擇三:使用 & 在父scope中執行函式
有時候從隔離scope中呼叫父scope中定義的函式是非常有必要的。為了能夠訪問外部scope中定義的函式,我們使用 &。比如我們想要從指令內部呼叫 sayHello() 方法。app.directive('sayHello', function() {
return {
scope: {
sayHelloIsolated: '&'
},
....
};
});
<body ng-controller="MainCtrl">
<input type="text" ng-model="color" />
<say-hello sayHelloIsolated="sayHello()"/>
</body>