angular.js最为强大的地方在于可以通过自定义指令来扩展html元素,这种思路与JSP的taglib类似,但在实现细节上更为自由,并且自定义指令也可以提供表单元素交互、数据绑定、事件处理功能。
创建自定义指令的基本格式为:
angular.module('myApp',[]).directive('myDirective',function(){ return { restrict :'EA', scope:true, template:``//ES6多行字符支持,模板文本字符串,也可使用templateUrl replace:true, transclude:true, link:function(){ //DOM operates. } } })
1.指令行为限制
A:用于限制属性,例如<div my-exp='something'></div>
E:用于限制元素,即可直接使用该指令作为html标签使用
C:用作html元素的class类。
2.指令作用域
最简单的做法是在创建自定义指令时将scope属性设置为 true从而共享父作用域,缺点是无法避免指令中修改父作用域的值。因此,通常的做法是为指令添加隔离作用域。在隔离作用域中,以下三个运算符的使用较为重要:
@:取DOM节点的属性值到隔离作用域中使用,
=:将$scope中的属性值与隔离作用域中的值进行双向绑定,
&:将$scope中的函数绑定到隔离作用域中(仅适用于函数)。
3.链接函数
自定义指令中可通过link函数修改DOM,通常被设置为一个postLink函数,实际上还可以设置一个preLink函数用于在元素链接之前执行。
以下示例提供了较为复杂的自定义指令,包含上述所有语法要点:
<!DOCTYPE HTML>
<html ng-app='myApp'>
<head>
<meta charset='utf-8'>
<title>Event key</title>
<style type="text/css">
.expander {
border: 1px solid black;
width: 250px;
}
.expander>.title {
background-color: black;
color: white;
padding: .1em .3em;
cursor: pointer;
}
.expander>.body {
padding: .1em .3em;
}
</style>
</head>
<body>
<div ng-controller='SomeController'>
<expander class='expander' title='title' click-fnc='clickFnc()'>
{{text}}
</expander>
</div>
</body>
<script src='http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js'></script>
<script>
var app = angular.module('myApp',[]);
app.controller('SomeController',function($scope){
$scope.title = 'Click to expand';
$scope.text = 'Some content inside this expander';
$scope.clickFnc = function(){
console.log("I'm clicked.");
}
})
.directive('expander',function(){
return {
restrict:'EA',
replace:true,
transclude:true,
scope: {
title: '=title',
clickFnc: '&clickFnc'
},
template:`<div>
<div class='title' ng-click='toggle();clickFnc()'>{{title}}</div>
<div class='body' ng-show='showMe' ng-transclude></div>
</div>`,
link:{
pre:function preLink(scope,element,attrs){
console.log("Pre link");
},
post:function postLink(scope,element,attrs){
console.log("Post link.");
scope.showMe = false;
scope.toggle = function toggle(){
scope.showMe = !scope.showMe;
}
}
}
}
});
</script>
</body>
</html>