<html ng-app="demoForDirective">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script src="./lib/angular.js">script>
<script src="./js/app.js">script>
<script src="./js/controller.js">script>
head>
<body>
<div ng-controller='demoForDirectiveController'>
<testdirective testdirective-title='title'>
{{text}}
testdirective>
div>
<div>
分数:<input type="text" attrsdirective/><br/>
div>
<div ng-controller="SomeController">
<accordion>
<expander class="expander"
ng-repeat="expander in expanders"
expander-title="expander.title">
{{expander.text}}
expander>
accordion>
div>
body>
html>
/**
* Created by jywl on 2016/7/7.
*/
var demoForDirective = angular.module('demoForDirective', ['demoForDirective.controller']);
demoForDirective.directive('testdirective', function () {
return {
restrict: 'EA',
replace: true,
transclude: true,
scope: {
title: '=testdirectiveTitle'
},
template: ''
+ '{{title}}'
+ ''
+ '',
link: function (scope, element, attrs) {
scope.showMe = false;
scope.toggle = function toggle() {
scope.showMe = !scope.showMe;
}
}
}
});
demoForDirective.directive('attrsdirective', function () {
return {
link: function (scope, elements, attrs, controller) {
elements[0].onkeyup = function () { //从元素列表中获取元素,并绑定相应的事件
//下面的意思是,如果输入10以内的数,则输入框边框颜色不变,否则变为红色
if (isNaN(this.value) || this.value < 1 || this.value > 10) {
this.style.borderColor = 'red';
}
else {
this.style.borderColor = '';
}
};
}
}
});
demoForDirective.directive('accordion', function () {
return {
restrict: 'EA',
replace: true,
transclude: true,
template: '',
controller: function () { //声明一个内部的controller,用于传递值和方法
var expanders = [];
this.gotOpened = function (selectedExpander) {
//angularJS的forEach用法
/*var objs =[{a:1},{a:2}];
angular.forEach(objs, function(data,index,array){
//data等价于array[index]
console.log(data.a+'='+array[index].a);
});
参数如下:
objs:需要遍历的集合
data:遍历时当前的数据
index:遍历时当前索引
array:需要遍历的集合,每次遍历时都会把objs原样的传一次。
* */
angular.forEach(expanders, function (expander) {
if (selectedExpander != expander) {
expander.showMe = false;
}
});
}
this.addExpander = function (expander) {
expanders.push(expander);
}
}
}
});
demoForDirective.directive('expander', function () {
return {
restrict: 'EA',
replace: true,
transclude: true,
require: '^?accordion',//意思是将accordion的控制器传到指令中,从而在下方使用它的函数 ^的意思是需要遍历dom树,?的意思是找不到不报错
scope: {
title: '=expanderTitle'
},
template: ''
+ '{{title}}'
+ ''
+ '',
link: function (scope, element, attrs, accordionController) {
scope.showMe = false;
accordionController.addExpander(scope);
scope.toggle = function toggle() {
scope.showMe = !scope.showMe;
accordionController.gotOpened(scope);
}
}
}
});
/**
* Created by jywl on 2016/7/7.
*/
angular.module('demoForDirective.controller', [])
.controller('demoForDirectiveController', function ($scope) {
$scope.title = '点击展开';
$scope.text = '这里是内部的内容。';
})
.controller('SomeController', function ($scope) {
$scope.expanders = [
{title: 'click me', text: 'one click'},
{title: 'click me two', text: 'two click'},
{title: 'click me three', text: 'three click'}];
});
主要详解app.js中关于指令的代码,大部分代码都有注释,如果还有不清楚的可以留言,我看到会及时回复的。
priority(优先级)- 当有多个directive定义在同一个DOM元素时,有时需要明确它们的执行顺序。这属性用于在directive的compile function调用之前进行排序。如果优先级相同,则执行顺序是不确定的(经初步试验,优先级高的先执行,同级时按照类似栈的“后绑定先执行”。另外,测试时有点不小心,在定义directive的时候,两次定义了一个相同名称的directive,但执行结果发现,两个compile或者link function都会执行)。据官方说,ng-repeate的优先级是1000。该属性默认值为0。
terminal(最后一组)- 如果设置为”true”,则表示当前的priority将会成为最后一组执行的directive。任何directive与当前的优先级相同的话,他们依然会执行,但顺序是不确定的(虽然顺序不确定,但基本上与priority的顺序一致。当前优先级执行完毕后,更低优先级的将不会再执行)。
scope - 如果设置为:
true - 将为这个directive创建一个新的scope作用域,而不是继承父作用域。
false - 默认值,使用现有的scope作用域。
{/属性名和绑定风格/} - 独立的scope。
独立scope与一般的scope的区别在于它不是通过原型继承于父scope的。这对于创建可复用的组件是很有帮助的,可以有效防止读取或者修改父级scope的数据。
绑定策略
@或@attr - 建立一个local scope property到DOM属性的绑定。因为属性值总是String类型,所以这个值总是返回一个字符串。如果没有通过@attr指定属性名称,那么本地名称将与DOM属性的名称一致。例如
,widget的scope定义为:{localName:’@myAttr’}
。那么,widget scope property的localName会映射出”hello {{name}}”转换后的真实值。name属性值改变后,widget scope的localName属性也会相应地改变(仅仅单向,与下面的”=”不同)。name属性是在父scope读取的。
=或=expression(绑定当前属性,它带来一个来自指令父scope的属性) - 在本地scope属性与parent scope属性之间设置双向的绑定。如果没有指定attr名称,那么本地名称将与属性名称一致。例如,widget定义的scope为:{localModel:’=myAttr’},那么widget scope property “localName”将会映射父scope的“parentModel”。如果parentModel发生任何改变,localModel也会发生改变,反之亦然。(双向绑定)
&或&attr - 传递一个来自父scope的函数,稍后调用。
controller - controller 构造函数。controller会在pre-linking步骤之前进行初始化,并允许其他directive通过指定名称的require进行共享(看下面的require属性)。这将允许directive之间相互沟通,增强相互之间的行为。
controller默认注入了以下本地对象:
$scope - 与当前元素结合的scope
$element - 当前的元素
$attrs - 当前元素的属性对象
$transclude - (A transclude linking function pre-bound to the correct transclusion scope)
require - 请求另外的controller,传入当前directive的linking function中。require需要传入一个directive controller的名称。如果找不到这个名称对应的controller,那么将会抛出一个error。名称可以加入以下前缀:
? - 不要抛出异常。这使这个依赖变为一个可选项。
^ - 允许查找父元素的controller
restrict - EACM的子集的字符串,它限制directive为指定的声明方式。如果省略的话,directive将仅仅允许通过属性声明:
E - 元素名称:
A - 属性名:
C - class名:
M - 注释 :
template - 如果replace 为true,则将模版内容替换当前的HTML元素,并将原来元素的属性、class一并迁移;如果为false,则将模版元素当作当前元素的子元素处理。
templateUrl - 与template基本一致,但模版通过指定的url进行加载。因为模版加载是异步的,所以compilation、linking都会暂停,等待加载完毕后再执行。
replace - 如果设置为true,那么模版将会替换当前元素,而不是作为子元素添加到当前元素中。(注:为true时,模版必须有一个根节点)
transclude - 编译元素的内容,使它能够被directive所用。(如果当前元素,希望其他directive调用,就将其设为true,并在元素的节点上,增加 就好,更高级的用法,目前我还在学习中)
true - 转换这个directive的内容。(这个感觉上,是直接将内容编译后搬入指定地方)
element - 转换整个元素,包括其他优先级较低的directive。(像将整体内容编译后,当作一个整体(外面再包裹p),插入到指定地方)
compile - 编译函数,整个运行周期中只执行一遍。(一般情况下,用compile即可。)
link - 链接函数,可以多次执行。具体用法参照上文代码