### 18.8. 指令定義時的參數
指令定義時的參數如下:
- name
- priority
- terminal
- scope
- controller
- require
- restrict
- template
- templateUrl
- replace
- transclude
- compile
- link
現在我們開始一個一個地吃掉它們……,但是并不是按順序講的。
_priority_ 這個值設置指令的權重,默認是 `0` 。當一個節點中有多個指令存在時,就按著權限從大到小的順序依次執行它們的 `compile` 函數。相同權重順序不定。_terminal_ 是否以當前指令的權重為結束界限。如果這值設置為 `true` ,則節點中權重小于當前指令的其它指令不會被執行。相同權重的會執行。_restrict_ 指令可以以哪些方式被使用,可以同時定義多種方式。
- E 元素方式 `<my-directive></my-directive>`
- A 屬性方式 `<div my-directive="exp"> </div>`
- C 類方式 `<div class="my-directive: exp;"></div>`
- M 注釋方式 `<!-- directive: my-directive exp -->`
_transclude_ 前面已經講過基本的用法了。可以是 `'element'` 或 `true` 兩種值。_compile_ 基本的定義函數。 `function compile(tElement, tAttrs, transclude) { ... }`_link_ 前面介紹過了。大多數時候我們不需要單獨定義它。只有 `compile` 未定義時 `link` 才會被嘗試。 `function link(scope, iElement, iAttrs, controller) { ... }`_scope_ scope 的形式。 `false` 節點的 scope , `true` 繼承創建一個新的 scope , `{}` 不繼承創建一個新的隔離 scope 。 `{@attr: '引用節點屬性', =attr: '把節點屬性值引用成scope屬性值', &attr: '把節點屬性值包裝成函數'}`_controller_ 為指令定義一個 controller , `function controller($scope, $element, $attrs, $transclude) { ... }`_name_ 指令的 controller 的名字,方便其它指令引用。_require_ 要引用的其它指令 conroller 的名字, `?name` 忽略不存在的錯誤, `^name` 在父級查找。_template_ 模板內容。_templateUrl_ 從指定地址獲取模板內容。_replace_ 是否使用模板內容替換掉整個節點, `true` 替換整個節點, `false` 替換節點內容。
<a b></a>
var app = angular.module('Demo', [], angular.noop);
app.directive('a', function(){
var func = function(element, attrs, link){
console.log('a');
}
return {compile: func,
priority: 1,
restrict: 'EA'};
});
app.directive('b', function(){
var func = function(element, attrs, link){
console.log('b');
}
return {compile: func,
priority: 2,
//terminal: true,
restrict: 'A'};
});
上面幾個參數值都是比較簡單且容易理想的。
再看 _scope_ 這個參數:
<div ng-controller="TestCtrl">
<div a b></div>
</div>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('a', function(){
4 var func = function(element, attrs, link){
5 return function(scope){
6 console.log(scope);
7 }
8 }
910 return {compile: func,
11 scope: true,
12 restrict: 'A'};
13 });
1415 app.directive('b', function(){
16 var func = function(element, attrs, link){
17 return function(scope){
18 console.log(scope);
19 }
20 }
2122 return {compile: func,
23 restrict: 'A'};
24 });
2526 app.controller('TestCtrl', function($scope){
27 $scope.a = '123';
28 console.log($scope);
29 });
對于 _scope_ :
- 默認為 `false` , `link` 函數接受的 `scope` 為節點所在的 `scope` 。
- 為 `true` 時,則 `link` 函數中第一個參數(還有 `controller` 參數中的 `$scope` ), `scope` 是節點所在的 `scope` 的 `child scope` ,并且如果節點中有多個指令,則只要其中一個指令是 `true` 的設置,其它所有指令都會受影響。
這個參數還有其它取值。當其為 `{}` 時,則 `link` 接受一個完全隔離(isolate)的 `scope` ,于 `true` 的區別就是不會繼承其它 `scope` 的屬性。但是這時,這個 `scope` 的屬性卻可以有很靈活的定義方式:
_@attr_ 引用節點的屬性。
<div ng-controller="TestCtrl">
<div a abc="here" xx="{{ a }}" c="ccc"></div>
</div>
var app = angular.module('Demo', [], angular.noop);
app.directive('a', function(){
var func = function(element, attrs, link){
return function(scope){
console.log(scope);
}
}
return {compile: func,
scope: {a: '@abc', b: '@xx', c: '@'},
restrict: 'A'};
});
app.controller('TestCtrl', function($scope){
$scope.a = '123';
});
- _@abc_ 引用 div 節點的 abc 屬性。
- _@xx_ 引用 div 節點的 xx 屬性,而 xx 屬性又是一個變量綁定,于是 `scope` 中 `b` 屬性值就和 `TestCtrl` 的 `a` 變量綁定在一起了。
- _@_ 沒有寫 attr name ,則默認取自己的值,這里是取 div 的 c 屬性。
_=attr_ 相似,只是它把節點的屬性值當成節點 `scope` 的屬性名來使用,作用相當于上面例子中的 _@xx_ :
<div ng-controller="TestCtrl">
<div a abc="here"></div>
</div>
var app = angular.module('Demo', [], angular.noop);
app.directive('a', function(){
var func = function(element, attrs, link){
return function(scope){
console.log(scope);
}
}
return {compile: func,
scope: {a: '=abc'},
restrict: 'A'};
});
app.controller('TestCtrl', function($scope){
$scope.here = '123';
});
_&attr_ 是包裝一個函數出來,這個函數以節點所在的 `scope` 為上下文。來看一個很爽的例子:
<div ng-controller="TestCtrl">
<div a abc="here = here + 1" ng-click="show(here)">這里</div>
<div>{{ here }}</div>
</div>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('a', function(){
4 var func = function(element, attrs, link){
5 return function llink(scope){
6 console.log(scope);
7 scope.a();
8 scope.b();
910 scope.show = function(here){
11 console.log('Inner, ' + here);
12 scope.a({here: 5});
13 }
14 }
15 }
1617 return {compile: func,
18 scope: {a: '&abc', b: '&ngClick'},
19 restrict: 'A'};
20 });
2122 app.controller('TestCtrl', function($scope){
23 $scope.here = 123;
24 console.log($scope);
2526 $scope.show = function(here){
27 console.log(here);
28 }
29 });
scope.a 是 _&abc_ ,即:
scope.a = function(){here = here + 1}
只是其中的 `here` 是 `TestCtrl` 的。
scope.b 是 _&ngClick_ ,即:
scope.b = function(){show(here)}
這里的 `show()` 和 `here` 都是 `TestCtrl` 的,于是上面的代碼最開始會在終端輸出一個 `124` 。
當點擊“這里”時,這時執行的 `show(here)` 就是 `llink` 中定義的那個函數了,與 `TestCtrl` 無關。但是,其間的 `scope.a({here:5})` ,因為 `a` 執行時是 `TestCtrl` 的上下文,于是向 `a` 傳遞的一個對象,里面的所有屬性 `TestCtrl` 就全收下了,接著執行 `here=here+1` ,于是我們會在屏幕上看到 `6` 。
這里是一個上下文交錯的環境,通過 _&_ 這種機制,讓指令的 `scope` 與節點的 `scope` 發生了互動。真是鬼斧神工的設計。而實現它,只用了幾行代碼:
case '&': {
parentGet = $parse(attrs[attrName]);
scope[scopeName] = function(locals) {
return parentGet(parentScope, locals);
}
break;
}
再看 _controller_ 這個參數。這個參數的作用是提供一個 controller 的構造函數,它會在 `compile` 函數之后, `link` 函數之前被執行。
<a>haha</a>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('a', function(){
4 var func = function(){
5 console.log('compile');
6 return function(){
7 console.log('link');
8 }
9 }
1011 var controller = function($scope, $element, $attrs, $transclude){
12 console.log('controller');
13 console.log($scope);
1415 var node = $transclude(function(clone_element, scope){
16 console.log(clone_element);
17 console.log('--');
18 console.log(scope);
19 });
20 console.log(node);
21 }
2223 return {compile: func,
24 controller: controller,
25 transclude: true,
26 restrict: 'E'}
27 });
`controller` 的最后一個參數, `$transclude` ,是一個只接受 `cloneAttachFn` 作為參數的一個函數。
按官方的說法,這個機制的設計目的是為了讓各個指令之間可以互相通信。參考普通節點的處理方式,這里也是處理指令 `scope` 的合適位置。
<a b>kk</a>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('a', function(){
4 var func = function(){
5 }
6 7 var controller = function($scope, $element, $attrs, $transclude){
8 console.log('a');
9 this.a = 'xx';
10 }
1112 return {compile: func,
13 name: 'not_a',
14 controller: controller,
15 restrict: 'E'}
16 });
1718 app.directive('b', function(){
19 var func = function(){
20 return function($scope, $element, $attrs, $controller){
21 console.log($controller);
22 }
23 }
2425 var controller = function($scope, $element, $attrs, $transclude){
26 console.log('b');
27 }
2829 return {compile: func,
30 controller: controller,
31 require: 'not_a',
32 restrict: 'EA'}
33 });
_name_ 參數在這里可以用以為 `controller` 重起一個名字,以方便在 _require_ 參數中引用。
_require_ 參數可以帶兩種前綴(可以同時使用):
- _?_ ,如果指定的 controller 不存在,則忽略錯誤。即:
require: '?not_b'
如果名為 `not_b` 的 controller 不存在時,不會直接拋出錯誤, `link` 函數中對應的 `$controller` 為 `undefined` 。
- _^_ ,同時在父級節點中尋找指定的 controller ,把上面的例子小改一下:
<a><b>kk</b></a>
把 `a` 的 _require_ 改成(否則就找不到 `not_a` 這個 controller ):
require: '?^not_a'
還剩下幾個模板參數:
_template_ 模板內容,這個內容會根據 _replace_ 參數的設置替換節點或只替換節點內容。_templateUrl_ 模板內容,獲取方式是異步請求。_replace_ 設置如何處理模板內容。為 `true` 時為替換掉指令節點,否則只替換到節點內容。
<div ng-controller="TestCtrl">
<h1 a>原始內容</h1>
</div>
var app = angular.module('Demo', [], angular.noop);
app.directive('a', function(){
var func = function(){
}
return {compile: func,
template: '<p>標題 {{ name }} <button ng-click="name=\'hahaha\'">修改</button></p>',
//replace: true,
//controller: function($scope){$scope.name = 'xxx'},
//scope: {},
scope: true ,
controller: function($scope){console.log($scope)},
restrict: 'A'}
});
app.controller('TestCtrl', function($scope){
$scope.name = '123';
console.log($scope);
});
_template_ 中可以包括變量引用的表達式,其 `scope` 遵尋 _scope_ 參數的作用(可能受繼承關系影響)。
_templateUrl_ 是異步請求模板內容,并且是獲取到內容之后才開始執行指令的 `compile` 函數。
最后說一個 _compile_ 這個參數。它除了可以返回一個函數用為 `link` 函數之外,還可以返回一個對象,這個對象能包括兩個成員,一個 _pre_ ,一個 _post_ 。實際上, `link` 函數是由兩部分組成,所謂的 _preLink_ 和 _postLink_ 。區別在于執行順序,特別是在指令層級嵌套的結構之下, _postLink_ 是在所有的子級指令 `link` 完成之后才最后執行的。 _compile_ 如果只返回一個函數,則這個函數被作為 _postLink_ 使用:
<a><b></b></a>
1 var app = angular.module('Demo', [], angular.noop);
2 3 app.directive('a', function(){
4 var func = function(){
5 console.log('a compile');
6 return {
7 pre: function(){console.log('a link pre')},
8 post: function(){console.log('a link post')},
9 }
10 }
1112 return {compile: func,
13 restrict: 'E'}
14 });
1516 app.directive('b', function(){
17 var func = function(){
18 console.log('b compile');
19 return {
20 pre: function(){console.log('b link pre')},
21 post: function(){console.log('b link post')},
22 }
23 }
2425 return {compile: func,
26 restrict: 'E'}
27 });
- Introduction
- 關于AngularJS
- 關于本文檔
- 開始的例子
- 依賴注入
- 作用域
- 數據綁定與模板
- 數據->模板
- 模板->數據
- 數據->模板->數據->模板
- 模板
- 定義模板內容
- 內容渲染控制
- 節點控制
- 事件綁定
- 表單控件
- 模板中的過濾器
- 排序 orderBy
- 過濾列表 filter
- 其它
- 例子:表頭排序
- 例子:搜索
- 錨點路由
- 路由定義
- 參數定義
- 業務處理
- 定義模板變量標識標簽
- AJAX
- HTTP請求
- 廣義回調管理
- 工具函數
- 上下文綁定
- 對象處理
- 類型判定
- 其它服務
- 日志
- 緩存
- 計時器
- 表達式函數化
- 模板單獨使用
- 自定義模塊和服務
- 模塊和服務的概念與關系
- 定義模塊
- 定義服務
- 引入模塊并使用服務
- 附加模塊 ngResource
- 使用引入與整體概念
- 基本定義
- 基本使用
- 定義和使用時的占位量
- 實例
- AngularJS與其它框架的混用(jQuery, Dojo)
- 自定義過濾器
- 自定義指令directive
- 指令的使用
- 指令的執行過程
- 基本的自定義方法
- 屬性值類型的自定義
- Compile的細節
- transclude的細節
- 把節點內容作為變量處理的類型
- 指令定義時的參數
- Attributes的細節
- 預定義的 NgModelController
- 預定義的 FormController
- 示例:文本框
- 示例:模板控制語句 for
- 示例:模板控制語句 if/else