(1)自定义指令实质
说白了就是把自定义的指定替换成浏览器可以识别的HTML标签
(2)实例1(基本使用)
<!DOCTYPE html>
<html ng-app="myTest">
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script>
</head>
<body>
<hello></hello>
<script type="text/javascript">
var app = angular.module('myTest', [])
app.directive("hello",function(){
return {
restrict:'E',
template:'<div>hi angular</div>',
replace:true
}
});
</script>
</body>
</html>
对于<hello>标签浏览器是不认识的,所以浏览器唯一能够做的就是忽略这个标签,那么为了要让浏览器认识这个标签,我们需要使用angular js来定义hello指令。
运行之后的结果如下:
可以看出,<hello>实际上被替换为了<div>hi angular</div>,实际上这就是replace:true的作用
那么替换的内容是从哪里来的呢?显然就是在template中定义的。
还剩一个restrict,意思就是我们定义的指令可以作为什么形式使用
可选的值有四个,即AECM。
A attribute属性:当做属性来使用
<div hello></div>
E element元素:当做标签元素来使用
<hello></hello>
C class类:当做CSS样式来使用
<div class="hello"></div>
M comments注释:当做注释使用(这种方式在1.2版本下亲测不可用!)
<!-- directive:hello --> <div></div>
一般来说推荐,当做属性和元素来使用。
当想要在现有的html标签上扩展属性时,采用属性的方式。
当想要自定义标签时,采用标签的形式。
想要使用那种方式,必须要在定义directive中的restrict里面声明对应的字母
(3)实例2(transclude)
假如当前我们自定义了标签,但是标签中还含有子标签,如下,这时怎么在替换的时候仍然包含其中的子标签呢?
<!DOCTYPE html>
<html ng-app="myTest">
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script>
</head>
<body>
<hello>
<span>标签中原来内容1</span>
<span>标签中原来内容2</span>
</hello>
</body>
</html>
这时可以使用
transclude:true,同时将原来内容嵌套在指定位置来实现
<!DOCTYPE html>
<html ng-app="myTest">
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script>
</head>
<body>
<hello>
<span>标签中原来内容1</span>
<span>标签中原来内容2</span>
</hello>
<script type="text/javascript">
var app = angular.module('myTest', [])
app.directive("hello",function(){
return {
restrict:'E',
template:'<div>hi <span ng-transclude></span> angular</div>',
transclude:true
}
});
</script>
</body>
</html>
结果如下
生成的结构如下:
(4)实例3
先看实例
<span style="font-size: 13.3333px;"><!DOCTYPE html>
<html ng-app="expanderModule">
<head>
<meta charset="utf-8">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script>
</head>
<body>
<div ng-controller='SomeController'>
<expander class='expander' expander-title='title'>
{{text}}
</expander>
</div>
<script type="text/javascript">
var expanderModule=angular.module('expanderModule', [])
expanderModule.directive('expander', function() {
return {
restrict : 'EA',
replace : true,
transclude : true,
scope : {
title : '=expanderTitle'
},
template : '<div>'
+ '<div class="title" ng-click="toggle()">{{title}},{{showMe}}</div>'
+ '<div class="body" ng-show="showMe" ng-transclude></div>'
+ '</div>',
link : function(scope, element, attrs) {
scope.showMe = false;
scope.toggle = function toggle() {
scope.showMe = !scope.showMe;
}
}
}
});
expanderModule.controller('SomeController',function($scope) {
$scope.title = '点击展开';
$scope.text = '这里是内部的内容。';
});
</script>
</body>
</html></span>
看定义指令的源码,从上至下:
1.scope 用来定义指令的作用域,可以定义false、true和对象,最常见的就是定义一个对象,其中可以从父作用域访问变量、函数
这时,scope的结构如下:
scope: {
ownAttributeName1: 'BINDING_STRATEGY+字符串',
ownAttributeName2: 'BINDING_STRATEGY+标签中属性名称',...
}
这其中的BINDING_STRATEGY指的是绑定策略,也就是说指令的scope中的值是从哪来的
可以有3种取值
符号 | 说明 | 举例 |
@ | 传递一个字符串作为属性的值. | str : ‘@string’ |
= | 使用父作用域中的一个属性,绑定数据到指令的属性中. | name : ‘=username’ |
& | 使用父作用域中的一个函数,可以在指令中调用 | getName : ‘&getUserName’ |
scope : {
title : '=expanderTitle'
}
相当于指令scope中定义了一个名称为title的变量,就类似于在controller中定义变量$scope.name = "xxx"
而使用的绑定策略是'=',就是说绑定了一个父作用域中的属性
也就是说title绑定了标签中expander-title的值(这里注意一下, 绑定时使用驼峰命名,标签中使用时使用连接线。使用指令时也是这样,如定义时使用myDerect,页面使用时使用my-derect)
然后发现其中expander-title和父scope中的title绑定了,那么最终指令中的值就是父scope中的值,即"点击展开"
2.link
类似于controller中定义的function,完成指令scope的一些初始化工作
template : '<div>'
+ '<div class="title" ng-click="toggle()">{{title}},{{showMe}}</div>'
+ '<div class="body" ng-show="showMe" ng-transclude></div>'
+ '</div>',
link : function(scope, element, attrs) {
scope.showMe = false;
scope.toggle = function toggle() {
scope.showMe = !scope.showMe;
}
}
可以看到传入了scope( 可以理解为指令中的类似controller中的$scope),接着就可以在其中像controller一样,对scope中的变量、函数进行定义了
定义完成之后,就可以在template或templateUrl定义的HTML中使用了
(5)require与controller
1.引入
假如现在需要写2个指令,而其中都需要toString()这个方法,那么该怎么办呢?
显然不能每个指令的link中都定义一遍,那么能不能复用呢?
require就是为了实现指令间功能复用而定义的
而为了区别私有方法和公共方法,公共方法都写在controller中
看如下实例var app = angular.modeule('myapp',[]);
app.directive('common',function(){
return {
...
controller: function($scope){
this.method1 = function(){
};
this.method2 = function(){
};
},
...
}
});
app.directive('d1',function(){
return {
...
require: '?^common',
link: function(scope,elem,attrs,common){
scope.method1 = common.method1;
..
},
...
}
});
需要说明的是,
link方法的第四个参数实际上就是common指令的controller对象
可以发现,其中require使用了?^在公共模块名称前,这时告诉angular,^是往上寻找,找不到就抛异常;?表示找不到不会抛异常
2.使用
一般都是用在ngModel这个指令上,用来自定义验证等
3.实例
<!DOCTYPE html>
<html ng-app="formCheckModule">
<head>
<meta charset="utf-8">
<link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"> </script>
<script src="../lib/angular-messages.min.js"></script>
</head>
<body ng-controller='SomeController'>
<form name="userForm" novalidate >
<div class="form-group" ng-class="{'has-error':userForm.own.$touched && userForm.own.$invalid}">
<label>自定义</label>
<input type="text" name="own" class="form-control"
ng-model="main.own"
ng-maxlength="20" required
own />
<div ng-messages="userForm.own.$error" ng-if="userForm.own.$touched">
<p ng-message="isAdmin">测试不通过</p>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-danger">提交</button>
</div>
<pre>{{userForm.own.$error}}</pre>
</form>
<script type="text/javascript">
var formCheckModule=angular.module('formCheckModule', ['ngMessages']);
formCheckModule.controller('SomeController',function($scope) {
});
formCheckModule.directive("own",function(){
return {
require:'ngModel',
link:function(scope, element, attrs, modelController){
var customValidator = function (value) {
console.log(value);
var validity = ('test'==(value));
modelController.$setValidity("own", validity);
return validity ? value : undefined;
};
modelController.$formatters.push(customValidator);
modelController.$parsers.push(customValidator);
}
}
});
</script>
</body>
</html>
注意:1)函数中value就是表单中的数据
2)每次表单中数据修改都会进入
3)$setValidity就是设置$error中的值