標籤:
指令詳解
1.用directive()方法來定義指令
.directive(‘myDirective‘,function($timeout,userDefinedService){
return {};
});
該方法接受兩個參數:
name(字串):指令的名字,用來在視圖中引用特定的指令
factory_function(函數):該函數返回一個對象,其中定義了指令的全部行為
當AngularJS啟動應用時,會把第一個參數當做一個字串,並以此字串為名來來註冊第二個參數返回的對象。也可以返回一個函數代替對象來定義指令,當返回一個函數時,這個函數通常被稱為連結傳遞函數,利用它可以定義指令的連結功能。但是返回函數會限制定義指令時的自由度。
2.指令可以使用的設定選項
(1)restrict(字串)
告訴AngularJS這個指令在DOM中可以以何種形式被聲明,包括:
E(元素) <my-directive></my-directive>
A(屬性,預設值) <div my-directive="expression"></div>
C(類名) <div class="my-directive:expression;"></div>
這些選項可以混合使用,屬性時聲明指令最常用的方式,因為它能在包括老版本的IE瀏覽器在內的所有瀏覽器中正常工作,並且不需要在文檔頭部註冊新的標籤。
如何進行選擇,通常取決於定義的指令是否包含某個組件的核心行為(E),或者用額外的行為、狀態或者其他內容對某個核心組件進行修飾或拓展(A)
當編寫的模板還需要在其他指令中使用時,可以將這個模板緩衝起來,如:
<hello></hello>
var myApp=angular.module(‘myApp‘,[]);
myApp.run(function($templateCache){
$templateCache.put("index1.html","<div>Hello Everyone!</div>");
});
myApp.directive(‘hello‘,function($templateCache){
return{
restrict:‘AE‘,
template:$templateCache.get(‘index1.html‘),
repalce:true
}
})
(2)優先順序pripority(數值)
如果一個元素上具有兩個優先順序相同的指令,聲明在前面的那個會被優先調用。
ng-repeat是所有指令中優先順序最高的,其他的預設值為0,主要是從效能進行考慮的。
(3)terminal(布爾型)
該參數告訴AngularJS停止運行當前元素上比本指令優先順序低的指令,但是優先順序相同的指令仍會執行。
(4)template(字串或函數)
必須被設定為以下兩種形式:
a一段HTML文本
b一個可以接受兩個參數的函數,參數為tElement和tAttrs,並返回一個代表模板的字串。
模板字串中必須存在一個跟DOM元素,每一行末尾的反斜線能保證AngularJS正確解析多行字串。更好的選擇是使用templateUrl參數引用外部模板,因為多行文本難以閱讀和維護。
(5)templateUrl
可以是兩種類型:
a一個代表外部HTML檔案路徑的字串
b一個可以接受兩個參數的函數,參數為tElement和tAttrs,並返回一個外部HTML檔案路徑的字串
調用指令時會在後台通過Ajax來請求HTML模板檔案,在本地開發時,需要在後台運行一個本機伺服器來從檔案系統中載入HTML模板。模板載入是非同步,意味著編譯和連結要暫停,等待模板載入完成。
通過Ajax非同步載入大量的模板將嚴重拖慢一個用戶端應用的速度,可以提前將模板緩衝到一個定義模板的JS檔案中。
(6)replace(布爾型)
設定為true意味著模板會被當做子項目插入到調用此指令的元素內部。
<div some-directive></div>
.directive(‘someDirective‘,function(){
return{
template:‘<div>some stuff here</div>‘
};
})
結果:<div some-directive><div>some stuff here</div></div>
加入replace:true後,結果為:<div>some stuff here</div>
(7)scope(布爾型或對象)
scope設定為true時,會從父範圍繼承並建立一個新的範圍對象
隔離範圍最主要的應用情境是建立可複用的組件,組件可以在未知上下文中使用,並且可以避免汙染所處的外部範圍或不經意的汙染內部範圍。建立具有隔離範圍的指令需要將scope屬性設定為一個Null 物件{},這樣指令的模板就無法訪問外部範圍了。
<div ng-app="myApp"
ng-init="someProperty = ‘some data‘"></div>
<div ng-init="siblingProperty = ‘more data‘">
Inside Div Two: {{ aThirdProperty }}
<div ng-init="aThirdProperty = ‘data for 3rd property‘"
ng-controller="SomeCtrl">
Inside Div Three: {{ aThirdProperty }}
<div ng-controller="SecondCtrl">
Inside Div Four: {{ aThirdProperty }}
<br>
Outside myDirective: {{ myProperty }}
<div my-directive ng-init="myProperty = ‘wow, this is cool‘">
Inside myDirective: {{ myProperty }}
<div>
</div>
</div>
</div>
angular.module(‘myApp‘, [])
.controller(‘SomeCtrl‘, function($scope) {
// we can leave it empty, it just needs to be defined
})
.controller(‘SecondCtrl‘, function($scope) {
// also can be empty
})
.directive(‘myDirective‘, function() {
return {
restrict: ‘A‘,
//scope:true
}
})
結果為:Inside Div Two:
Inside Div Three: data for 3rd property
Inside Div Four: data for 3rd property
Outside myDirective: wow, this is cool
Inside myDirective: wow, this is cool
加上scope:true或scope:{}結果為:Outside myDirective:
Inside myDirective: wow, this is cool
例:
<div ng-conreoller="MainController">
Outside myDirective: {{ myProperty }}
<div my-directive ng-init="myProperty = ‘wow, this is cool‘">
Inside myDirective: {{ myProperty }}
<div>
</div>
angular.module(‘myApp‘, [])
.controller(‘MainController‘,function($scope){
})
.directive(‘myDirective‘, function() {
return {
restrict: ‘A‘,
scope: true,
priority:100,
template:‘<div>Inside myDirective:{{ myProperty }}</div>‘
};
})
Outside myDirective:
Inside myDirective:wow, this is cool
例:
<div ng-init="myProperty = ‘wow, this is cool‘"></div>
Surrounding scope: {{ myProperty }}
<div my-inherit-scope-directive="SomeCtrl">
Inside an directive with inherited scope: {{ myProperty }}
</div>
<div my-directive>
Inside myDirective, isolate scope: {{ myProperty }}
<div>
angular.module(‘myApp‘, [])
.directive(‘myDirective‘, function() {
return {
restrict: ‘A‘,
scope: {}
};
})
.directive(‘myInheritScopeDirective‘, function() {
return {
restrict: ‘A‘,
scope: true
};
})
Surrounding scope: wow, this is cool
Inside an directive with inherited scope: wow, this is cool
Inside myDirective, isolate scope:
(8)繫結原則
使用繫結原則將指令內部的隔離範圍同指令外部的範圍進行資料繫結
a本地範圍屬性:@/@attr 將本地範圍同DOM屬性的值進行綁定
b雙向繫結:=/=attr 將本地範圍上的屬性同父級範圍上的屬性進行雙向繫結
c父級範圍綁定:&/&attr 對這個值進行設定時會產生一個指向父級範圍的封裝函數
例:
<div ng-controller="myCtrl">
<drink flavor="{{ctrlFlavor}}"></drink>
</div>
var myApp=angular.module(‘myApp‘,[]);
myApp.controller(‘myCtrl‘,[‘$scope‘,function($scope){
$scope.ctrlFlavor="百威";
}]);
myApp.directive("drink",function(){
return{
restrict:‘AE‘,
template:"<div>{{flavor}}</div>",
link:function(scope,element,attrs){
scope.flavor=attrs.flavor;
}
}
})
相當於:
myApp.directive("drink",function(){
return{
restrict:‘AE‘,
scope:{
flavor:‘@‘
},
template:"<div>{{flavor}}</div>"
}
})
例:
<div ng-controller="myCtrl">
Ctrl:<br>
<input type="text" ng-model="ctrlFlavor"><br>
Directive:<br>
<drink flavor="ctrlFlavor"></drink>
</div>
var myApp=angular.module(‘myApp‘,[]);
myApp.controller(‘myCtrl‘,[‘$scope‘,function($scope){
$scope.ctrlFlavor="百威";
}]);
myApp.directive("drink",function(){
return{
restrict:‘AE‘,
scope:{
flavor:‘=‘
},
template:‘<input type="text" ng-model="flavor" />‘
}
})
修改其中一個,另一個會發生改變
(9)transclude(布爾型)
用來建立可複用的組件,典型的例子就是模態對話方塊或導覽列。
可以將整個模板,包括其中的指令通過嵌入全部傳入一個指令中。為了將範圍傳遞進去,scope參數的值必須通過{}或true設定成隔離範圍。
(10)controller(字串或函數)
angular.module(‘myapp‘,[])
.directive(‘myDirective‘,function(){
restrict:‘A‘,
controller:‘SomeController‘
})
同時要在同一個檔案或index.html包含的另一個檔案中設定控制器
angular.module(‘myapp‘,[])
.controller(‘SomeController‘,function($scope,$element,$attrs,$transclude){})
也可以在指令內部通過匿名建構函式的方式來定義一個內聯的控制器:
angular.module(‘myapp‘,[])
.directive(‘myDirective‘,function(){
restrict:‘A‘,
controller:function($scope,$element,$attrs,$transclude){
}
})
可以將任意可以被注入的AngularJS服務傳遞給控制器,只需將其注入到控制器中,就可以在指令中使用它。一些特殊的服務可以被注入到指令中,包括:
$scope:與指令元素相關聯的當前範圍
$element:當前指令對應的元素
$attrs:由當前元素的屬性群組成的對象
<div id="aDiv" class="box"></div>
{
id:"aDiv",
class:"box"
}
$transclude:嵌入連結函數會與對應的嵌入範圍進行預綁定
3.指令的生命週期
(1)載入階段:載入angularjs,找到ng-app,確定應用的邊界
編譯階段:
遍曆DOM,找到所有指令;
根據指令代碼中的template,replace,transclude轉換DOM結構;
如果有complie函數則調用;
連結階段:
對每一條指令運行link函數;
link函數一般用來操作DOM,綁定事件監聽器,監聽資料變化
(2)link函數的應用:
如果指令定義中有require選項,函數簽名中會有第四個參數,代表控制器或所依賴的指令額控制器
link:function(scope,element,attrs,SomeController){
}
其中,scope指令用來在其內部註冊監聽器的範圍,iElement參數代表執行個體元素,指的是使用此指令的元素,iAttrs參數代表執行個體屬性,是一個由定義在元素上的屬性群組成的標準化列表,可以在所有指令的連結函數間共用。controller參數指向require選項定義的控制器。
<div ng-controller="myCtrl">
<loader howToLoad="loadData()">滑動載入</loader>
</div>
myApp.directive(‘loader‘,function(){
return{
restrict:‘AE‘,
link:function(scope,element,attrs){
element.bind("mouseenter",function(){
//scope.loadData();
scope.$apply("loadData()");
})
}
};
})
在不同的controller中複用指令:
<div ng-controller="myCtrl">
<loader howToLoad="loadData()">滑動載入</loader>
</div>
<div ng-controller="myCtrl2">
<loader howToLoad="loadData2()">滑動載入</loader>
</div>
var myApp=angular.module(‘myApp‘,[]);
myApp.controller(‘myCtrl‘,[‘$scope‘,function($scope){
$scope.loadData=function(){
console.log(‘資料載入中111‘);
}
}]);
myApp.controller(‘myCtrl2‘,[‘$scope‘,function($scope){
$scope.loadData2=function(){
console.log(‘資料載入中222‘);
}
}]);
myApp.directive(‘loader‘,function(){
return{
restrict:‘AE‘,
link:function(scope,element,attrs){
element.bind("mouseenter",function(){
scope.$apply(attrs.howtoload);
})
}
};
})
指令的複用:
<div class="row">
<div class="col-md-3">
<superman strength>動感超人</superman>
</div>
<div class="col-md-3">
<superman strength speed>動感超人2---力量+敏捷</superman>
</div>
<div class="col-md-3">
<superman strength speed light>動感超人3---力量+敏捷+發光</superman>
</div>
</div>
var myApp=angular.module(‘myApp‘,[]);
myApp.directive("superman",function(){
return{
scope:{},
restrict:‘AE‘,
controller:function($scope){
$scope.abilities=[];
this.addStrength=function(){
$scope.abilities.push("strength");
};
this.addSpeed=function(){
$scope.abilities.push("speed");
};
this.addLight=function(){
$scope.abilities.push("light");
};
},
link:function(scope,element,attrs){
element.addClass(‘btn btn-primary‘);
element.bind("mouseenter",function(){
console.log(scope.abilities);
});
}
}
});
myApp.directive("strength",function(){
return{
require:‘^superman‘,
link:function(scope,element,attrs,supermanCtrl){
supermanCtrl.addStrength();
}
}
});
myApp.directive("speed",function(){
return{
require:‘^superman‘,
link:function(scope,element,attrs,supermanCtrl){
supermanCtrl.addSpeed();
}
}
});
myApp.directive("light",function(){
return{
require:‘^superman‘,
link:function(scope,element,attrs,supermanCtrl){
supermanCtrl.addLight();
}
}
});
獨立scope:
<hello></hello>
<hello></hello>
<hello></hello>
<hello></hello>
var myApp=angular.module(‘myApp‘,[]);
myApp.directive("hello",function(){
return{
restrict:‘AE‘,
template:‘<div><input type="text" ng-model="username" />
{{username}}</div>‘,
replace:true
}
})
點擊其中一個輸入框,所有的輸入框及其後面內容都變化。只需加入scope:{},所有的輸入框內容互不影響
angularJS 指令二