您的位置:首页 > Web前端 > AngularJS

AngularJS 指令

2015-10-09 17:36 826 查看

指令

对于指令,可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素的功能。

指令格式

angular.application('myApp', [])
.directive('myDirective', function() {
// 一个指令定义对象
return {
// 通过设置项来定义指令,在这里进行覆写
};
});


当AngularJS启动应用时,它会把第一个参数当作一个字符串,并以此字符串为名来注册第二个参数返回的对象。AngularJS编译器会解析主HTML的DOM中的元素、属性、注释和CSS类名中使用了这个名字的地方,并在这些地方引用对应的指令。当它找到某个已知的指令时,就会在页面中插入指令所对应的DOM元素。

指令的工厂函数只会在编译器第一次匹配到这个指令时调用一次。和controller函数类似,
$injetor.invoke
可以被用来调用指令的工厂函数。

当AngularJS在DOM中遇到具名的指令时,会去匹配已经注册过的指令,并通过名字在注册过的对象中查找。此时,就开始了一个指令的生命周期,指令的生命周期开始于
$compile
方法并结束于
$link
方法。

指令全部设置选项

angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function:
function(tElement, tAttrs) {...},
templateUrl: String,
replace: Boolean,
scope: Boolean or Object,
transclude: Boolean or String,
controller: String or function(scope, element, attrs, transclude,
otherInjectables) { ... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) { ... },
compile: // 返回一个对象或连接函数,如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) { ... },
post: function(scope, iElement, iAttrs, controller) { ... }
}
// 或者
return function postLink(...) { ... }
}
};
});


[b]restrict(字符串)[/b]

EACM的子集的字符串,它限制directive为指定的声明方式。如果省略的话,directive将仅仅允许通过属性声明:

类型描述示例
E元素名称
<my-directive></my-directive>
A属性
<div my-directive="exp"></div>
C样式
<div class="my-directive:exp;"></div>
M注释
<!-- directive: my-directive exp -->
[b]priority(数值型)[/b]

优先级参数可以被设置为一个数值。大多数指令会忽略这个参数,使用默认值0,但也有些场景设置高优先级是非常重要甚至是必须的。例如,ngRepeat将这个参数设置为1000,这样就可以保证在同一元素上,它总是在其他指令之前被调用。如果一个元素上具有两个优先级相同的指令,声明在前面的那个会被优先调用。

示例:
ngRepeat
在遍历元素的过程中,我们需要Angular首先生成模板元素的拷贝,然后再应用其他指令。

如果不这样做,其他指令就会被应用到标准模板元素(未拷贝前)上,而不会应用到需要的遍历元素上。

[b]termina(布尔型)[/b]

高优先级指令会先执行。这个参数如果设置为”true”,则表示当前的priority将会成为最后一组执行的指令。任何directive与当前的优先级相同的话,他们依然会执行,但顺序是不确定的(虽然顺序不确定,但基本上与priority的顺序一致)。当前优先级执行完毕后,更低优先级的将不会再执行。

[b]template(字符串或函数)[/b]

如果replace 为true,则将模版内容替换当前的HTML元素,并将原来元素的属性、class一并迁移;如果为false,则将模版元素当作当前元素的子元素处理。

[b]templateUrl[/b]

与template基本一致,但模版通过指定的url进行加载。因为模版加载是异步的,所以compilation、linking都会暂停,等待加载完毕后再执行。

[b]replace[/b]

如果设置为true,那么模板将会替换当前元素(并且应用原元素的所有属性),否则,将模板作为子元素添加到当前元素中。(:为true时,模版必须有一个根节点)

[b]transclude[/b]

通过transclude属性将内容插入新的模板。当此属性设置为true的时候,指令会删掉原来的内容,使你的模板可以用
ng-transclusde
指令进行重新插入。

app.directive('hello', function() {
return {
template: '<div>Hi there <span ng-transclude></span></div>',
transclude: true
};
});


1.使用以下内容运行它:

<div hello>Bob</div>


结果:

<div hello>
<div>Hi there <span ng-transclude><span class="ng-scope">Bob</span></span>
</div>
</div>


2.使用以下内容运行它:

<div hello><p>Bob</p></div>


结果:

<div hello>
<div>Hi there <span ng-transclude><p class="ng-scope">Bob</p></span>
</div>
</div>


[b]controller[/b]

创建一个控制器,它会暴露一个API,利用这个API可以在多个指令间进行通信。(见*《用AngularJS开发下一代Web应用》*P135)

[b]require[/b]

要求必须存在另一个指令,当前指令才能正确运行,例(
^?myDirective
): 在当前指令中传入另一个含控制器(为了暴露API)的指令,进行多指令通信。

类型描述示例
?默认Angular未找到控制器会抛出异常,?表示该控制器是可选的,没找到,不抛出异常。
?myDirective
^默认Angular从同一元素上的命名指令中获取控制器。^表示允许遍历DOM树查找指令,获取controller。
^myDirective
[b]compile[/b]

用来对模板自身进行转换,仅仅在编译阶段执行一次。

//compile函数会接收模板元素及其属性列表,所以函数形参带t前缀。
function compile ( tElement, tAttrs, transclude) { … }


[b]link[/b]

负责在模型和视图之间进行动态关联,link函数会执行很多次——对于指令的每个实例,link函数都会执行一次。

//link函数会接受视图实例对象,视图实例是使用模板创建的,所以函数形参带i前缀。
function link( scope, iElement, iAttrs, controller) { … }


注意 post-link function: 仅仅在这里执行DOM转换是安全的。

[b]scope[/b]

类型取值
现有scopefalse(默认值)
新scopetrue
独立scope{/* 属性名和绑定风格 */}
{/* 属性名和绑定风格 */} - 将创建一个新的、独立(isolate)的scope。独立scope与一般的scope的区别在于它不是通过原型继承于父scope的。这对于创建可复用的组件是很有帮助的,可以有效防止读取或者修改父级scope的数据。

@或@attr - 建立一个local scope property到DOM属性的绑定。因为属性值总是String类型,所以这个值总是返回一个字符串。如果没有通过@attr指定属性名称,那么本地名称将与DOM属性的名称一致。例如
<widget my-attr="hello {{name}}">
,widget的scope定义为:
{localName:'@myAttr'}
。那么,widget scope property的localName会映射出”hello {{name}}”转换后的真实值。name属性值改变后,widget scope的localName属性也会相应地改变(仅仅单向,与下面的”=”不同)。name属性是在父scope读取的(不是组件scope)

=或=attr - 在本地scope属性与parent scope属性之间设置双向的绑定。如果没有指定attr名称,那么本地名称将与属性名称一致。例如
<widget my-attr="parentModel">
,widget定义的scope为:
{localModel:'=myAttr'}
,那么widget scope property “localModel”将会映射父scope的“parentModel”。如果parentModel发生任何改变,localModel也会发生改变,反之亦然。(双向绑定)

&或&attr - 提供一个在父scope上下文中执行一个表达式的途径。如果没有指定attr的名称,那么local name将与属性名称一致。例如
<widget my-attr="changeAttr()">
,widget的scope定义为:
{localFn:'&myAttr'}
,那么isolate scope property “localFn”会指向changeAttr的function。

学习链接

示例

<!DOCTYPE html>
<html ng-app="ZippyModule">
<head>
<title>ZippyModule</title>
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"/>
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<style type="text/css">
.zippy {
border: 1px solid black;
display: inline-block;
width: 250px;
}
.zippy.opened > .title:before { content: '▼ '; }
.zippy.opened > .body { display: block; }
.zippy.closed > .title:before { content: '► '; }
.zippy.closed > .body { display: none; }
.zippy > .title {
background-color: black;
color: white;
padding: .1em .3em;
cursor: pointer;
}
.zippy > .body {
padding: .1em .3em;
}
</style>
<script src="scripts/vendor/angular/angular.js"
type="text/javascript"></script>
</head>
<body>
<div ng-controller="MyCtrl">
Title: <input ng-model="title"><br/>
Text: <textarea ng-model="text" ></textarea>
<hr/>
<div class="zippy" zippy-title="Details:{{title}}...">{{text}}</div>
</div>
<script type="text/javascript">
var myModule = angular.module("ZippyModule", []);
myModule.controller("MyCtrl", function ($scope) {
$scope.title = "这里是标题";
$scope.text = "这里是内容哇。。。";
});
myModule.directive('zippy', function () {
return {
template: '<div>' +
' <div class="title">{{title}}</div>' +
' <div class="body" ng-transclude></div>' +
'</div>',
replace: true,
transclude: true,
restrict: 'C',
scope: {
title:"@zippyTitle"
},
link: function(scope, element, attrs) {
var title = angular.element(element.children()[0]);
opened = false;

title.bind("click", toogle);
element.addClass("closed");

function toogle() {
opened = !opened;
element.removeClass(opened ? "closed" : "opened");
element.addClass(opened ? "opened" : "closed");
}
}
};
});
</script>
</body>
</html>


推荐阅读: 《AngularJS权威教程》 & Developer Guide/Directives & 借眼观世界 & 好用插件 & 学习资源
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: