AngularJS为我们提供了自定义指令的功能,通过此功能,我们可以自定义一些标签,为我们的开发提供帮助,其实一些大型公司都存在自定义标签,为快速开发提供了基础。
定义自定义指令一般有两种方式
1.第一种,在module()的第三个参数中定义
代码如下:
index01.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index01.js" ></script>
</head>
<body ng-controller="myController">
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为属性
-->
<div my-directive></div>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为标签
-->
<my-directive></my-directive>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为类名
-->
<div class="myDirective"></div>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为注释
-->
<!--
directive:myDirective
-->
</body>
</html>
index01.js
angular.module("myApp",[],['$compileProvider',function($compileProvider){
$compileProvider.directive("myDirective",function(){
return {
"restrict":"ECMA",/*E-element,C-class,M 注释,A-attribute*/
"template":"<h1>hello,directive</h1>",
'replace':true/*将html页面引用这个指令的标签替换掉*/
}
});
}])
.controller("myController",function($scope){});
2.第二种定义自定义指令方式-基于directive的方式
index02.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index02.js" ></script>
</head>
<body>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为属性
-->
<div my-directive></div>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为标签
-->
<my-directive></my-directive>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为类名
-->
<div class="myDirective"></div>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为注释
-->
<!--
directive:myDirective
-->
</body>
</html>
index02.js
angular.module("myApp",[])
.directive("myDirective",function(){
return {
"restrict":'ECMA',
"template":"<h1>hello,directive1.</h1>",
"replace":true//用replace时,必须要有一个节点包裹才能替换
/*
* templateUrl:导入模板的路径
*
* */
}
});
测试templateUrl的用法
index03.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index03.js" ></script>
</head>
<body>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为属性
-->
<div my-directive></div>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为标签
-->
<my-directive></my-directive>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为类名
-->
<div class="myDirective"></div>
<!--
作者:1404578601@qq.com
时间:2016-10-24
描述:作为注释
-->
<!--
directive:myDirective
-->
</body>
</html>
index003.html
<h1>this is a templateUrl test.</h1>
index03.js
angular.module("myApp",[])
.directive("myDirective",function(){
return {
"restrict":"ECMA",
"templateUrl":"index003.html",
"replace":true
}
});
transclude属性-是否保留原标签内的内容
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index04.js" ></script>
</head>
<body>
<div my-directive1>this is my div.</div>
</body>
</html>
i
ndex.js
angular.module("myApp",[])
.directive("myDirective1",function(){
return {
"restrict":"ECMA",
"template":"<h2>this is directive1.<p ng-transclude></p></h2>",
"replace":true,
"transclude":true//保存原标签内的值
}
});
priority属性-指令在模块中执行的优先级别
terminal属性-是否以当前指令的权重为结束界限
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index05.js" ></script>
</head>
<body>
<div my-directive1 my-directive2></div>
</body>
</html>
index.js
angular.module("myApp",[])
.directive("myDirective1",function(){
return {
"restrict":"ECMA",
"template":"<h3>this is directive1.</h3>",
"replace":true,
"priority":0
}
})
.directive("myDirective2",function(){
return {
"restrict":"ECMA",
"template":"<h3>this is directive2.</h3>",
"replace":true,
"priority":10,
"terminal":true
}
});
compile属性和link属性
要使用compile和link,首先了解AngularJS指令的编译过程:
1.第一阶段:
标准浏览器API的转化—-就是将html转化为dom。
2.第二阶段:
AngularJS的compile—-搜索匹配directive,按照priority排序,并执行directive上的compile方法
3.第三阶段:
AngularJS link—–执行directive上的link方法,进行scope绑定及事件绑定。
compile
- compile方法的定义为:compile:function(tElement,tAttris,transclude).
- compile函数用来对模板自身进行转换仅仅在编译阶段运行一次
- compile中直接返回的函数是postlink,表示link参数需要执行的函数,也可以返回一个对象里面包含prelink和postlink。
- 当定义compile参数时,将无视link参数,因为compile里返回的就是该指令需要执行的link函数。
link
- link方法的定义为:link:function(scope,iElement,iAttris,controller).
- link函数代表的是compile函数返回的postlink。
- prelink表示在编译阶段后,指令连接到子元素之前运行,
- postlink表示在所有的子元素都连接之后运行
- link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次。
compile和link的使用动机
compile
想在dom渲染前对它进行变形(如添加节点等),并且不需要scope参数,想在所有相同directive里共享某些方法,这时应该定义在compile里,性能会比较好,返回值就是link函数,这时就是共同使用的时候。
link
对特定的元素注册事件,需要用到scope参数来实现dom元素的一些行为
代码演示:
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index06.js" ></script>
</head>
<body>
<div my-directive></div>
</body>
</html>
index.js
angular.module("myApp",[])
.directive("myDirective",function(){
return {
"restrict":"ECMA",
"template":"<h1>this is testController.</h1>",
"controller":function($scope){
console.log("controller...");//进行值的传递
},
"compile":function(tElement,tAttris,transclude){
/*
* compile:返回值就是link函数,在指令编译过程的第三阶段运行
*
* */
return {
//编译阶段之后,指令连接子元素之前
"pre":function preList(){
console.log("pre...");
},
//在编译阶段之后,指令连接子元素之后
"post":function postList(){
console.log("post");
}
}
},
}
});
controller和controllerAs属性:
controller
为自定义的指令添加一个控制器,使得多个指令之间可以通信
controllerAs
为controller定义一个别名
代码演示:
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index08.js" ></script>
</head>
<body>
<div my-directive></div>
</body>
</html>
index.js
angular.module("myApp",[])
.directive("myDirective",function(){
return {
"restrict":"ECMA",
"template":"<div><h3>this is controller test.</h3>{{name}}</div>",
"controller":function($scope){
$scope.name='this is controller.';
},
"controllerAs":"myControl",
"link":function(scope,iElement,iAttris,myControl){
console.log(scope.name);
iElement.on("click",function(){
alert("hello,angularjs.")
});
}
}
});
运行结果如下:
require属性—可以将其它指令传递给自己
- directiveName 通过驼峰法的命名制定控制器应该带有那个指令,默认会从同一个元素上的指令
- ^directiveName 从父级查找指令
- ?directiveName 表示指令是可选的,如果找不到,也不会抛出异常
代码演示如下:
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index07.js" ></script>
</head>
<body>
<div my-directive></div>
</body>
</html>
index.js
angular.module("myApp",[])
.directive("myDirective",function(){
return {
"restrict":"ECMA",
"template":"<div><ul><li ng-repeat='book in books'>{{book.name}}</li></ul><book-add></book-add></div>",
"controller":function($scope){
$scope.books=[{
"name":"嘻游记",
"id":12
},{
"name":"东游记",
"id":13
}];
this.addBook=function(){
$scope.$apply(function(){
$scope.books.push({
"name":"哈游记",
"id":11
});
});
}
},
"controllerAs":"booklist",
"replace":true
}
})
.directive("bookAdd",function(){
return {
"restrict":"ECMA",
"require":"^myDirective",
"template":"<button>添加课本</button>",
"replace":true,
"link":function(scope,iElement,iAttris,booklist){
iElement.on("click",booklist.addBook);
}
}
});
scope属性—新定义一个作用域,而不是继承的父级作用域
var myApp = angular.module("myApp",[]);
myApp
.directive("myDirective",function() {
return {
"restrict" : "AEMC",
"template" : "<div><ul><li ng-repeat='book in books'>{{book.name}}</li></ul></div>",
"controller" : function($scope) {
console.info($scope)
},
/**
* scope默认为false,表示使用同一个作用域,
* 但是当我们设置为true时,此时,就是controller
* 的作用域就是一个独立的作用域
*/
"scope" : true,
"replace" : true
}
})
.controller("myCon",["$scope",function($scope) {
console.info($scope)
}]);
如果默认或者scope设置为false,则所有的controller默认一个作用域,但是当我们设置scope为真的时候,该controller则是一个独立的作用域。
- false 继承父级元素的作用域
- true 创建一个新的作用域,但是可以向上得到父级作用域
- object 独立的scope,父级无法得到,作用域链是断的
- object的参数:
- &:作用域把父级作用域的属性包装成了一个函数,从而以函数的方式读写父作用域的属性。
- =:作用域的属性与父作用域进行了双向绑定,任何一方的修改均影响到对方。
- @:只能读取父作用域里的值单向绑定。
代码演示如下:
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="../js/angular-1.3.14.min.js" ></script>
<script type="text/javascript" src="index09.js" ></script>
</head>
<body ng-controller="myCon">
{{books}}==={{msg}}
<div my-directive bb="books" parent-books="books" scope-books="{{msg}}"></div>
</body>
</html>
index.js
var myApp = angular.module("myApp",[]);
myApp
.directive("myDirective",function() {
return {
"restrict" : "AEMC",
"template" : "<div><ul><li ng-repeat='book in books'>{{book.name}}====={{msg}}</li></ul></div>",
"controller" : function($scope) {
// console.info($scope.$parent.books)
// $scope.books = $scope.$parent.books;
$scope.books = $scope.aaa();
// $scope.books = $scope.bbb;
// $scope.bbb.push({
// "name" : "PHP",
// "price" : 30
// });
console.info($scope.ccc)
$scope.msg = $scope.ccc;
$scope.msg = "哈哈";
},
/**
* scope默认为false,表示使用同一个作用域,
* 但是当我们设置为true时,此时,就是controller
* 的作用域就是一个独立的作用域
*/
// "scope" : true,
/**
* 当scope是一个对象的时候,作用域也是一个
* 独立的作用域,但是无法共享父级作用域
*/
"scope" : {
//将父元素中的books封装成a函数
aaa: "&bb",
//数据与父元素双向绑定
// bbb: "=parentBooks",
//注意,只能传递字符串等基本数据类型,
//子类修改值,父类不会受到影响
ccc: "@scopeBooks"
},
"replace" : true
}
})
.controller("myCon",["$scope","$rootScope",function($scope,rs) {
$scope.books = [
{
"name" : "javascript",
"price" : 15.6
},{
"name" : "java",
"price" : 20
}
];
$scope.msg = "this is a test.";
// console.info($scope);
// console.log(rs)
}]);