对于指令,可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素的功能。
首先来看个完整的参数示例再来详细的介绍各个参数的作用及用法:
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 or String,scope: Boolean or Object,transclude: Boolean,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,iAttrs,controller) { ... },post: function(scope,controller) { ... } } return function postLink(...) { ... } } }; });
restrict[string]
restrict:说明指令在HTML中的应用形式,备选项有"A"、"E" 和 "C", "M" ,分别代表 attribute、element、class和comment(注释),(默认值为"A")。
priority[int]
大多数指令会忽略这个参数,使用默认值0,但也有些场景设置高优先级是非常重要甚至是必须的。例如,ngRepeat将这个参数设置为1000,这样就可以保证在同一元素上,它总是在其他指令之前被调用。
terminal[bool]
这个参数用来停止运行当前元素上比本指令优先级低的指令。但同当前指令优先级相同的指令还是会被执行。
例如:ngIf的优先级略高于ngView(它们操控的实际就是terminal参数),如果ngIf的表达式值为true,ngView就可以被正常执行,但如果ngIf表达式的值为false,由于ngView的优先级较低就不会被执行。
template[string or function]
template参数是可选的,必须被设置为以下两种形式之一:
1.一段HTML文本;
2.一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符串。tElement和tAttrs中的t代表template,是相对于instance的。
templateUrl[string or function]
templateUrl是可选的参数,可以是以下类型:
1.一个代表外部HTML文件路径的字符串;
2.一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件路径的字符串。
无论哪种方式,模板的URL都将通过ng内置的安全层,特别是$getTrustedResourceUrl,这样可以保护模板不会被不信任的源加载。 默认情况下,调用指令时会在后台通过Ajax来请求HTML模板文件。加载大量的模板将严重拖慢一个客户端应用的速度。为了避免延迟,可以在部署应用之前对HTML模板进行缓存。
replace[bool]
replace是一个可选参数,如果设置了这个参数,值必须为true,因为默认值为false。默认值意味着模板会被当作子元素插入到调用此指令的元素内部,
scope参数[bool or object]
scope参数是可选的,可以被设置为true或一个对象。默认值是false。
当我们改变scope的值我们会发现
false:继承但不隔离
true:继承并隔离
{}:隔离且不继承 ,即单独制定绑定字段和方式
scope: { // 设置指令对于的scope
name: "@",// name 值传递 (字符串,单向绑定)
amount: "=",// amount 引用传递(双向绑定)
save: "&" // 保存操作
}
transclude
transclude是一个可选的参数。默认值是false。嵌入通常用来创建可复用的组件,典型的例子是模态对话框或导航栏。我们可以将整个模板,包括其中的指令通过嵌入全部传入一个指令中。指令的内部可以访问外部指令的作用域,并且模板也可以访问外部的作用域对象。为了将作用域传递进去,scope参数的值必须通过{}或true设置成隔离作用域。如果没有设置scope参数,那么指令内部的作用域将被设置为传入模板的作用域。
controller[string or function]
controller参数可以是一个字符串或一个函数。当设置为字符串时,会以字符串的值为名字,来查找注册在应用中的控制器的构造函数.
我们可以将任意可以被注入的ng服务注入到控制器中,便可以在指令中使用它了。控制器中也有一些特殊的服务可以被注入到指令当中。这些服务有:
1. $scope 与指令元素相关联的当前作用域。
2. $element 当前指令对应的元素。
3. $attrs 由当前元素的属性组成的对象。
<div id="aDiv"class="Box"></div> 具有如下的属性对象: { id: "aDiv",class: "Box" }4. $transclude 嵌入链接函数会与对应的嵌入作用域进行预绑定。transclude链接函数是实际被执行用来克隆元素和操作DOM的函数。
controllerAs[string]
controllerAs参数用来设置控制器的别名,这样就可以在视图中引用控制器甚至无需注入$scope。
<div ng-controller="MainController as main"> <input type="text" ng-model="main.name" /> <span>{{ main.name }}</span> </div>JsCode:
angular.module('myApp',[]) .controller('MainController',function () { this.name = "Halower"; });控制器的别名使路由和指令具有创建匿名控制器的强大能力。这种能力可以将动态的对象创建成为控制器,并且这个对象是隔离的、易于测试。
require[string or string[]]
require为字符串代表另外一个指令的名字。require会将控制器注入到其所指定的指令中,并作为当前指令的链接函数的第四个参数。字符串或数组元素的值是会在当前指令的作用域中使用的指令名称。在任何情况下,ng编译器在查找子控制器时都会参考当前指令的模板。
- 如果不使用^前缀,指令只会在自身的元素上查找控制器。指令定义只会查找定义在指令作当前用域中的ng-model=""
- 如果使用?前缀,在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数。
- 如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器。
- 如果添加了?^ 将前面两个选项的行为组合起来,我们可选择地加载需要的指令并在父指令链中进行查找
- 如果没有任何前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器(或具有指定名字的指令)就抛出一个错误
compile选项本身并不会被频繁使用,但是link函数则会被经常使用。本质上,当我们设置了link选项,实际上是创建了一个postLink() 链接函数,以便compile() 函数可以定义链接函数。通常情况下,如果设置了compile函数,说明我们希望在指令和实时数据被放到DOM中之前进行DOM操作,在这个函数中进行诸如添加和删除节点等DOM操作是安全的。
compile和link选项是互斥的。如果同时设置了这两个选项,那么会把compile所返回的函数当作链接函数,而link选项本身则会被忽略。
编译函数负责对模板DOM进行转换。链接函数负责将作用域和DOM进行链接。 在作用域同DOM链接之前可以手动操作DOM。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。
link: function (scope,controller) {…}
链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。
link: 该方法在指令中扮演着重要的角色。它负责执行DOM 操作和注册事件监听器等。link 方法包含以下参数:
scope: 指令Scope的引用。scope 变量在初始化时是不被定义的,link 方法会注册监视器监视值变化事件。
element: 包含指令的DOM元素的引用, link 方法一般通过jQuery 操作实例(如果没有加载jQuery,还可以使用Angular's jqLite )。
controller: 在有嵌套指令的情况下使用。这个参数作用在于把子指令的引用提供给父指令,允许指令之间进行交互, tab 指令就是使用该参数较典型的例子:http://jsfiddle.net/powertoolsteam/GBE7N/1/
注意,当调用link 方法时, 通过值传递("@")的scope 变量将不会被初始化,它们将会在指令的生命周期中另一个时间点进行初始化,如果你需要监听这个事件,可以使用scope.$watch 方法。