指令定義時(shí)的參數(shù)如下:
現(xiàn)在我們開始一個(gè)一個(gè)地吃掉它們……,但是并不是按順序講的。
0
。當(dāng)一個(gè)節(jié)點(diǎn)中有多個(gè)指令存在時(shí),就按著權(quán)限從大到小的順序依次執(zhí)行它們的 compile
函數(shù)。相同權(quán)重順序不定。true
,則節(jié)點(diǎn)中權(quán)重小于當(dāng)前指令的其它指令不會(huì)被執(zhí)行。相同權(quán)重的會(huì)執(zhí)行。<my-directive></my-directive>
<div my-directive="exp"> </div>
<div class="my-directive: exp;"></div>
<!-- directive: my-directive exp -->
'element'
或 true
兩種值。function compile(tElement, tAttrs, transclude) { ... }
compile
未定義時(shí) link
才會(huì)被嘗試。 function link(scope, iElement, iAttrs, controller) { ... }
false
節(jié)點(diǎn)的 scope , true
繼承創(chuàng)建一個(gè)新的 scope , {}
不繼承創(chuàng)建一個(gè)新的隔離 scope 。 {@attr: '引用節(jié)點(diǎn)屬性', =attr: '把節(jié)點(diǎn)屬性值引用成scope屬性值', &attr: '把節(jié)點(diǎn)屬性值包裝成函數(shù)'}
function controller($scope, $element, $attrs, $transclude) { ... }
?name
忽略不存在的錯(cuò)誤, ^name
在父級(jí)查找。true
替換整個(gè)節(jié)點(diǎn), false
替換節(jié)點(diǎn)內(nèi)容。<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'}; });
上面幾個(gè)參數(shù)值都是比較簡單且容易理想的。
再看 scope 這個(gè)參數(shù):
<div ng-controller="TestCtrl"> <div a b></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: true, restrict: 'A'}; }); app.directive('b', function(){ var func = function(element, attrs, link){ return function(scope){ console.log(scope); } } return {compile: func, restrict: 'A'}; }); app.controller('TestCtrl', function($scope){ $scope.a = '123'; console.log($scope); });
對(duì)于 scope :
false
, link
函數(shù)接受的 scope
為節(jié)點(diǎn)所在的 scope
。true
時(shí),則 link
函數(shù)中第一個(gè)參數(shù)(還有 controller
參數(shù)中的 $scope
), scope
是節(jié)點(diǎn)所在的 scope 的 child scope ,并且如果節(jié)點(diǎn)中有多個(gè)指令,則只要其中一個(gè)指令是 true 的設(shè)置,其它所有指令都會(huì)受影響。這個(gè)參數(shù)還有其它取值。當(dāng)其為 {}
時(shí),則 link
接受一個(gè)完全隔離(isolate)的 scope
,于 true
的區(qū)別就是不會(huì)繼承其它 scope
的屬性。但是這時(shí),這個(gè) scope
的屬性卻可以有很靈活的定義方式:
@attr 引用節(jié)點(diǎn)的屬性。
<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'; });
scope
中 b
屬性值就和 TestCtrl
的 a
變量綁定在一起了。=attr 相似,只是它把節(jié)點(diǎn)的屬性值當(dāng)成節(jié)點(diǎn) scope
的屬性名來使用,作用相當(dāng)于上面例子中的 @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 是包裝一個(gè)函數(shù)出來,這個(gè)函數(shù)以節(jié)點(diǎn)所在的 scope
為上下文。來看一個(gè)很爽的例子:
<div ng-controller="TestCtrl"> <div a abc="here = here + 1" ng-click="show(here)">這里</div> <div>{{ here }}</div> </div>
var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(element, attrs, link){ return function llink(scope){ console.log(scope); scope.a(); scope.b(); scope.show = function(here){ console.log('Inner, ' + here); scope.a({here: 5}); } } } return {compile: func, scope: {a: '&abc', b: '&ngClick'}, restrict: 'A'}; }); app.controller('TestCtrl', function($scope){ $scope.here = 123; console.log($scope); $scope.show = function(here){ console.log(here); } });
scope.a 是 &abc ,即:
scope.a = function(){here = here + 1}
只是其中的 here
是 TestCtrl
的。
scope.b 是 &ngClick ,即:
scope.b = function(){show(here)}
這里的 show()
和 here
都是 TestCtrl
的,于是上面的代碼最開始會(huì)在終端輸出一個(gè) 124
。
當(dāng)點(diǎn)擊“這里”時(shí),這時(shí)執(zhí)行的 show(here)
就是 llink
中定義的那個(gè)函數(shù)了,與 TestCtrl
無關(guān)。但是,其間的 scope.a({here:5})
,因?yàn)?nbsp;a
執(zhí)行時(shí)是 TestCtrl
的上下文,于是向 a
傳遞的一個(gè)對(duì)象,里面的所有屬性 TestCtrl
就全收下了,接著執(zhí)行 here=here+1
,于是我們會(huì)在屏幕上看到 6
。
這里是一個(gè)上下文交錯(cuò)的環(huán)境,通過 & 這種機(jī)制,讓指令的 scope
與節(jié)點(diǎn)的 scope
發(fā)生了互動(dòng)。真是鬼斧神工的設(shè)計(jì)。而實(shí)現(xiàn)它,只用了幾行代碼:
case '&': { parentGet = $parse(attrs[attrName]); scope[scopeName] = function(locals) { return parentGet(parentScope, locals); } break; }
再看 controller 這個(gè)參數(shù)。這個(gè)參數(shù)的作用是提供一個(gè) controller 的構(gòu)造函數(shù),它會(huì)在 compile
函數(shù)之后, link
函數(shù)之前被執(zhí)行。
<a>haha</a>
var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(){ console.log('compile'); return function(){ console.log('link'); } } var controller = function($scope, $element, $attrs, $transclude){ console.log('controller'); console.log($scope); var node = $transclude(function(clone_element, scope){ console.log(clone_element); console.log('--'); console.log(scope); }); console.log(node); } return {compile: func, controller: controller, transclude: true, restrict: 'E'} });
controller
的最后一個(gè)參數(shù), $transclude
,是一個(gè)只接受 cloneAttachFn
作為參數(shù)的一個(gè)函數(shù)。
按官方的說法,這個(gè)機(jī)制的設(shè)計(jì)目的是為了讓各個(gè)指令之間可以互相通信。參考普通節(jié)點(diǎn)的處理方式,這里也是處理指令 scope
的合適位置。
<a b>kk</a>
var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(){ } var controller = function($scope, $element, $attrs, $transclude){ console.log('a'); this.a = 'xx'; } return {compile: func, name: 'not_a', controller: controller, restrict: 'E'} }); app.directive('b', function(){ var func = function(){ return function($scope, $element, $attrs, $controller){ console.log($controller); } } var controller = function($scope, $element, $attrs, $transclude){ console.log('b'); } return {compile: func, controller: controller, require: 'not_a', restrict: 'EA'} });
name 參數(shù)在這里可以用以為 controller
重起一個(gè)名字,以方便在 require 參數(shù)中引用。
require 參數(shù)可以帶兩種前綴(可以同時(shí)使用):
not_b
的 controller 不存在時(shí),不會(huì)直接拋出錯(cuò)誤, link
函數(shù)中對(duì)應(yīng)的 $controller
為 undefined
。a
的 require 改成(否則就找不到 not_a
這個(gè) controller ):require: '?^not_a'
還剩下幾個(gè)模板參數(shù):
true
時(shí)為替換掉指令節(jié)點(diǎn),否則只替換到節(jié)點(diǎn)內(nèi)容。<div ng-controller="TestCtrl"> <h1 a>原始內(nèi)容</h1> </div>
var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(){ } return {compile: func, template: '<p>標(biāo)題 {{ 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 中可以包括變量引用的表達(dá)式,其 scope
遵尋 scope 參數(shù)的作用(可能受繼承關(guān)系影響)。
templateUrl 是異步請(qǐng)求模板內(nèi)容,并且是獲取到內(nèi)容之后才開始執(zhí)行指令的 compile
函數(shù)。
最后說一個(gè) compile 這個(gè)參數(shù)。它除了可以返回一個(gè)函數(shù)用為 link
函數(shù)之外,還可以返回一個(gè)對(duì)象,這個(gè)對(duì)象能包括兩個(gè)成員,一個(gè) pre ,一個(gè) post 。實(shí)際上, link
函數(shù)是由兩部分組成,所謂的 preLink 和 postLink 。區(qū)別在于執(zhí)行順序,特別是在指令層級(jí)嵌套的結(jié)構(gòu)之下, postLink 是在所有的子級(jí)指令 link
完成之后才最后執(zhí)行的。 compile 如果只返回一個(gè)函數(shù),則這個(gè)函數(shù)被作為 postLink 使用:
<a><b></b></a>
var app = angular.module('Demo', [], angular.noop); app.directive('a', function(){ var func = function(){ console.log('a compile'); return { pre: function(){console.log('a link pre')}, post: function(){console.log('a link post')}, } } return {compile: func, restrict: 'E'} }); app.directive('b', function(){ var func = function(){ console.log('b compile'); return { pre: function(){console.log('b link pre')}, post: function(){console.log('b link post')}, } } return {compile: func, restrict: 'E'} });
更多建議: