Angular指令概述
指令是一種執(zhí)行的信號(hào),一旦發(fā)布了這個(gè)指令,就要執(zhí)行某項(xiàng)動(dòng)作,HTML中的標(biāo)簽都可以理解為指令,但Angular中的指令要復(fù)雜很多,不但要?jiǎng)?chuàng)建元素,還要給元素附加某些特定的行為,因此,Angular中的指令是一個(gè)在特定DOM元素上執(zhí)行的函數(shù)
指令定義的基礎(chǔ)
在Angular中,定義指令需要調(diào)用directive
方法,該方法接收兩個(gè)參數(shù):
var app = angular.module('myapp', []);
app.directive(name, fn);
在定義的模塊上使用directive
方法創(chuàng)建一個(gè)指令,name為指令的名稱,fn是一個(gè)函數(shù),它將返回一個(gè)對(duì)象,在這個(gè)對(duì)象中,定義了這個(gè)指令的全部行為
<div>
<ts-hello></ts-hello>
<div ts-hello></div>
<div class="ts-hello"></div>
<div data-ts-hello></div>
</div>
<script>
var app = angular.module('myapp', []);
app.directive('tsHello', function () {
return {
restrict: 'EAC',
template: '<h3>Hello, Angular!</h3>'
}
})
</script>
設(shè)置指令對(duì)象的基礎(chǔ)屬性
replace
:它的屬性值是布爾類型,當(dāng)該屬性值為true時(shí),表示用模板中的內(nèi)容替換指令標(biāo)記,否則則不替換,直接顯示指令標(biāo)記,默認(rèn)為false
templateUrl
:它的屬性值是一個(gè)URL地址,該地址指向一個(gè)模板頁面
<div>
<ts-tplfile></ts-tplfile>
<ts-tplscript></ts-tplscript>
<ts-tplcache></ts-tplcache>
</div>
<script>
var app = angular.module('myapp', []);
app.run(function ($templateCache) {
$templateCache.put('cache', '<h3>模板內(nèi)容來源于緩存</h3>')
});
app.directive('tsTplfile', function () {
return {
restrict: 'EAC',
templateUrl: 'tpl.html'
};
});
app.directive('tsTplscript', function () {
return {
restrict: 'EAC',
templateUrl: 'tpl',
replace: true
}
});
app.directive('tsTplcache', function () {
return {
restrict: 'EAC',
templateUrl: 'cache'
}
});
</script>
Angular指令對(duì)象的重要屬性
指令對(duì)象中的transclude屬性
transclude
屬性的值是布爾值,默認(rèn)為false,表示不開啟,如果設(shè)置為true,則開啟該屬性,當(dāng)開啟后,則可以在模板中通過ng-transclude
方式替換指令元素中的內(nèi)容
<ts-hello>
<div>我是自定義指令在HTML里的內(nèi)容</div>
</ts-hello>
<script>
var app = angular.module('MyApp', []);
app.directive('tsHello', function () {
return {
restrict: 'EA',
template: '<div ng-transclude></div>',
replace: true,
transclude: true
}
});
</script>
指令對(duì)象中的link屬性
指令對(duì)象中的link
屬性的值是一個(gè)函數(shù),在該函數(shù)中可以操控DOM元素對(duì)象,包括綁定元素的各類事件,定義事件觸發(fā)時(shí)執(zhí)行的內(nèi)容
link: function(scope, element, attrs) {
// ...
}
link
函數(shù)包含3個(gè)主要的參數(shù):
-
scope
參數(shù)表示指令所在的作用域 -
element
參數(shù)表示指令中的元素,改元素可以通過Angular內(nèi)部封裝的jqLite框架進(jìn)行調(diào)用 -
attrs
參數(shù)表示指令元素的屬性集合通過這個(gè)參數(shù)可以獲取元素中的各類屬性
<script type="text/ng-template" id="tpl">
<button>點(diǎn)擊按鈕</button>
</script>
<div>
<ts-tplscipt></ts-tplscipt>
<div>{{content}}</div>
</div>
<script>
var app = angular.module('myapp', []);
app.directive('tsTplscipt', function () {
return {
restrict: 'EAC',
templateUrl: 'tpl',
replace: true,
link: function (scope, element, attrs) {
element.bind('click', function () {
scope.$apply(function () {
scope.content = '這是點(diǎn)擊后顯示的內(nèi)容';
})
attrs.$$element[0].disabled = true;
})
}
}
});
</script>
指令對(duì)象中的compile屬性
該屬性比起link
屬性使用的很少,該屬性返回一個(gè)函數(shù)或?qū)ο蟆.?dāng)返回一個(gè)函數(shù)時(shí),該函數(shù)名稱為post
,而返回一個(gè)對(duì)象時(shí),該對(duì)象中則包含兩個(gè)名為pre
和post
方法函數(shù),這兩個(gè)函數(shù)名是系統(tǒng)提供的,不可修改。
<div ng-controller="myctrl">
<ts-a>
<ts-b>
{{tip}}
</ts-b>
</ts-a>
</div>
<script>
var app = angular.module('myapp', []);
app.controller('myctrl', function ($scope) {
$scope.tip = '跟蹤compile執(zhí)行過程';
});
app.directive('tsA', function () {
return {
restrict: 'EAC',
compile: function (tEle, tAttrs, trans) {
console.log('正在編譯A指令');
return {
pre: function (scope, element, attrs) {
console.log('正在執(zhí)行A指令中的pre函數(shù)');
},
post: function (scope, element, attr) {
console.log('正在執(zhí)行A指令中的post函數(shù)');
}
}
}
}
});
app.directive('tsB', function () {
return {
restrict: 'EAC',
compile: function (tEle, tAttrs, trans) {
console.log('正在編譯B指令');
return {
pre: function (scope, element, attrs) {
console.log('正在執(zhí)行B指令中pre函數(shù)');
},
post: function (scope, element, attrs) {
console.log('正在執(zhí)行B指令中的post函數(shù)');
}
}
}
}
});
</script>
Angular指令對(duì)象的scope屬性
在Angular指令對(duì)象中,scope
屬性使用頻率很高,它的值包含兩種類型,一種是布爾值,另一類是JSON對(duì)象
scope屬性是布爾值
使用scope
屬性自定義指令時(shí),默認(rèn)是布爾類型,初始值為false。在這種情況下,指令中的作用域就是指令元素所在的作用域。我們將指令中的作用域稱為子作用域,把指令元素所在作用域稱為父作用域,當(dāng)scope
為false
時(shí),子作用域和父作用域完全相同,一方變化,則另一方也會(huì)自動(dòng)發(fā)生變化
當(dāng)scope
為true
時(shí),則表示子作用域是獨(dú)立創(chuàng)建的,父作用域中內(nèi)容的改變會(huì)影響子作用域,但子作用域的內(nèi)容發(fā)生變化,并不會(huì)修改父作用域中的內(nèi)容
<script type="text/ng-template" id="tpl">
<div>{{message}}</div>
<button ng-transclude></button>
</script>
<div>
<input type="text" ng-model="message" placeholder="請(qǐng)輸入提示內(nèi)容">
<ts-message>固定</ts-message>
</div>
<script>
var app = angular.module('myapp', []);
app.directive('tsMessage', function () {
return {
restrict: 'EAC',
templateUrl: 'tpl',
transclude: true,
scope: true,
link: function (scope, element, attrs) {
element.bind('click', function () {
scope.$apply(function () {
scope.message = '這是單擊后的值';
})
})
}
}
})
</script>
第二個(gè)例子:
html:
<div ng-controller="myCtrl">
父親: {{name}}
<input ng-model="name">
<div my-directive></div>
</div>
var app = angular.module('myApp', [])
app.controller('myCtrl', ['$scope', function ($scope) {
$scope.name = 'leifeng';
}]);
app.directive('myDirective', function () {
return {
restrict: 'EA',
scope: true, //父作用域發(fā)生改變,子作用域會(huì)變化,子作用域的變化不會(huì)影響父作用域
template: '<div>兒子: {{name}}<input ng-model="name"></div>'
}
});
scope屬性是對(duì)象
除了將scope屬性設(shè)置為布爾值之外,還可以設(shè)置成一個(gè)JSON對(duì)象,如果是對(duì)象,那么父作用域與子作用域是完全獨(dú)立的,不存在任何關(guān)聯(lián)
app.directive('myDirective', function () {
return {
resrict: 'EA',
scope: {}, //父作用域與子作用域相互不影響,改變?nèi)我庖环蕉疾粫?huì)改變另一方
template: //....
}
})
這時(shí),子作用域中如果需要添加屬性,則可以通過link
函數(shù),在scope
上添加,如果子作用域需要與調(diào)用父作用域的屬性和方法,則需要在這個(gè)JSON對(duì)象中添加綁定策略
在JSON對(duì)象中添加的有3種綁定策略,分別是@
、=
和&
(1) @綁定
如果父作用域的屬性內(nèi)容修改了,子作用域?qū)?yīng)的屬性內(nèi)容也會(huì)隨之修改,而如果子作用域?qū)傩詢?nèi)容修改了,是不會(huì)影響父作用域?qū)?yīng)的屬性內(nèi)容的。
html:
<div ng-controller="myCtrl">
父親: {{name}}
<input ng-model="name">
<my-directive name="{{name}}"></my-directive>
</div>
javascript:
<script>
var app = angular.module('myApp', [])
app.controller('myCtrl', ['$scope', function ($scope) {
}]);
app.directive('myDirective', function () {
return {
restrict: 'EA',
scope: {
name: '@' //指令作用域中變量與父作用域中一致,直接使用@綁定
},
replace: true,
template: '<div>兒子: {{name}}<input ng-model="name"></div>'
}
});
</script>
(2) =綁定
=綁定
的功能是創(chuàng)建一個(gè)父作用域與子作用域可以同時(shí)共享的屬性,即父作用域修改了該屬性,子作用域也隨之改變,反之亦然。
html:
<div ng-controller="myCtrl">
<input type="text" ng-model="color" placeholder="Enter a color">
{{color}}
<hello-world color='color'></hello-world>
<!--注意上面自定義指令里屬性的寫法-->
</div>
javascript:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', ['$scope', function ($scope) {}]);
app.directive('helloWorld', function () {
return {
restrict: 'EA',
replace: true,
scope: {
color: '='
},
template: '<div style="background-color:{{color}}">Hello World<input type="text" ng-model="color"></div>'
}
});
</script>
(3) &綁定
&綁定
的功能可以在獨(dú)立的子作用域中直接調(diào)用父作用域的方法,在調(diào)用時(shí)可以向函數(shù)傳遞參數(shù)。
<div ng-controller="myCtrl">
<input type="text" ng-model="name" placeholder="Eneter a color">
{{name}}
<hello-world saysomething999="say();" name="kaindy"></hello-world>
</div>
javascript:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', ['$scope', function ($scope) {
$scope.say = function () {
alert('hello');
}
$scope.name = 'leifeng';
}]);
app.directive('helloWorld', function () {
return {
restrict: 'EA',
replace: true,
scope: {
saysomething: '&saysomething999',
name: '@'
},
template: '<button type="button" ng-bind="name" ng-init="saysomething();"></button>'
}
});
</script>
Angular指令對(duì)象的require和controller屬性
require
和controller
兩個(gè)屬性常用于多個(gè)自定義指令元素嵌套時(shí),即當(dāng)一個(gè)子元素指令需要與父元素指令通信時(shí),就需要使用這兩個(gè)屬性
require和controller屬性的概念
require
屬性在創(chuàng)建子元素指令時(shí)添加,它的屬性值用于描述與父元素指令通信時(shí)的方式,如^
符號(hào)表示向外層尋找指定名稱的指令,?
符號(hào)表示即使沒有找到,也不會(huì)出現(xiàn)異常
require: "^?myDirective"
controller
屬性值是一個(gè)構(gòu)造函數(shù),在創(chuàng)建父元素指令時(shí)添加,并可以在函數(shù)中創(chuàng)建多個(gè)屬性或方法。在添加后,這些屬性和方法都會(huì)被實(shí)例的對(duì)象所繼承,而這個(gè)實(shí)例對(duì)象則是子元素指令中link
函數(shù)的第4個(gè)參數(shù)
也就是說,當(dāng)在子元素指令中添加了require
屬性,并通過屬性值指定父元素指令的名稱,那么就可以通過子元素指令中link
函數(shù)的第4個(gè)參數(shù)來訪問父元素指令中controller
屬性添加的方法。
controller: function () {
this.a = function (childDirective) {
// 方法a的函數(shù)體
}
}
-
controller
的屬性值對(duì)應(yīng)一個(gè)構(gòu)造函數(shù) -
this
代表父元素指令本身 -
a
表示構(gòu)造函數(shù)中的一個(gè)任意的方法 -
childDirective
形參表示子元素指令中的scope
對(duì)象
html:
<div>
<!--父元素指令-->
<ts-parent>
<div>{{ptip}}</div>
<!--子元素指令-->
<ts-child>
<div>{{ctip}}</div>
</ts-child>
<button ng-click="click()">換位</button>
</ts-parent>
</div>
javascript:
<script>
var app = angular.module('myApp', []);
app.directive('tsParent', function () {
return {
restrict: 'EA',
controller: function ($scope, $compile, $http) {
this.addChild = function (c) {
$scope.ptip = '今天天氣不錯(cuò)!';
$scope.click = function () {
$scope.tmp = $scope.ptip;
$scope.ptip = c.ctip;
c.ctip = $scope.tmp;
}
}
}
}
});
app.directive('tsChild', function () {
return {
restrict: 'EA',
// 與父元素指令tsParent進(jìn)行通信
require: '^?tsParent',
// 第4個(gè)參數(shù)表示父元素指令本身,可以調(diào)用定義在其上的方法
link: function (scope, element, attrs, ctrl) {
scope.ctip = '氣溫正好18攝氏度';
ctrl.addChild(scope);
}
}
});
</script>