directive()
用来定义指令的:
angular.module('myApp', [])
.directive('myDirective', function($timeout, UserDefinedService) {
// 指令定义放在这里
return {
// 通过设置项来定义指令,在这里进行覆写
};
});
directive()
方法可以接受两个参数:
$compile
服务利用这个方法返回的对象来构造指令的行为12博体育,为了避免与未来的HTML标准冲突,12bet,给自定义的指令加入前缀来代表自定义的命名空间。AngularJS本身已经使用了
ng-
前缀,所以可以选择除此以外的名字。
当AngularJS在DOM中遇到具名的指令时,12bet,会去匹配已经注册过的指令,12bet,并通过名字在注册过的对象中查找。此时,就开始了一个指令的生命周期,指令的生命周期开始于$compile
方法并结束于link方法
12博体育,个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默认AngularJS认为restrict的值是A,即以属性的形式来进行声明:
<my-directive></my-directive>
<div my-directive="expression"></div>
<div class="my-directive:expression;"></div>
<--directive:my-directive expression-->
属性是用来声明指令最常用的方式,因为它能在包括老版本的IE浏览器在内的所有浏览器中正常工作,并且不需要在文档头部注册新的标签。
包含某个组件的核心行为时使用元素型。用额外的行为、状态或者其他内容进行修饰或扩展时使用属性型
如果一个元素上具有两个优先级相同的指令,声明在前面的那个会被优先调用。如果其中一个的优先级更高,则不管声明的顺序如何都会被优先调用:具有更高优先级的指令总是优先运行。
默认为0,ngRepeat为1000,是所有内置属性中最高的
告诉AngularJS停止运行当前元素上比本指令优先级低的指令。但同当前指令优先级相同的指令还是会被执行
template参数是可选的,必须被设置为以下两种形式之一:
tElement
和tAttrs
,并返回一个代表模板的字符串在实际生产中,更好的选择是使用templateUrl参数引用外部模板,因为多行文本阅读和维护起来都是一场噩梦。
可选的参数,可以是以下类型:
模板的URL都将通过AngularJS内置的安全层, 特别是$getTrustedResourceUrl
,这样可以保护模板不会被不信任的源加载
调用指令时会在后台通过Ajax来请求HTML模板文件,也就是说:
模板加载后,AngularJS会将它默认缓存到$templateCache
服务中,,可以提前将模板缓存到一个定义模板的JavaScript文件中,这样就不需要通过XHR来加载模板了
可选,默认为false,默认值意味着模板会被当作子元素插入到调用此指令的元素内部
scope参数是可选的,默认为false:
使用隔离作用域时,可以将指令内部的隔离作用 域,同指令外部的作用域进行数据绑定:
@
符号将本地作用域同DOM属性的值进行绑定=
可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定&
符号可以对父级作用域进行绑定,以便在其中运行函数可选,默认为false
可以将整个模板,包括其中的指令通过嵌入全部传入一个指令中。这样做可以将任意内容和作用域传递给指令。transclude参数就是用来实现这个目的的,指令的内部可以访问外部指令的作用域,并且模板也可以访问外部的作用域对象
只有当你希望创建一个可以包含任意内容的指令时,才使用transclude: true
可选:
可以向控制器中注入如下服务:
用来设置控制器的别名,可以以此为名来发布控制器,并且作用域可以访问controllerAs。这样就可以在视图中引用控制器,甚至无需注入$scope。
符串或数组元素的值是会在当前指令的作用域中使用的指令名称。require会将控制器注入到其值所指定的指令中,并作为当前指令的链接函数的第四个参数。
默认情况下,指令只会在自身的元素上查找控制器。可以用下面的前缀进行修饰,改变查找控制器时的行为:
?
: 如果在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数^
: 如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器?^
: 将前面两个选项的行为组合起来,可选择地加载需要的指令并在父指令链中进行查找在compile函数内部,只对DOM进行操作,返回函数等效于使用link配置,返回对象的话包含两个函数:
compile: function(tElement, tAttrs, transclude) {
// 一些DOM操作
return {
pre: function preLink(scope, iElement, iAttrs, controller) {},
post: function postLink(scope, iElement, iAttrs, controller) {}
};
}
link函数会访问scope对象,其返回一个postLink函数。如果在compile中返回了post,那么link选项就会被忽略
link: function postLink(scope, iElement, iAttrs){}
compile和link有许多异同:
AngularJS应用启动后会进行编译和链接,作用域会同HTML进行绑定,应用可以对用户在HTML中进行的操作进行实时响应。
$compile
方法来执行的。这个方法会遍历DOM并找到匹配的指令。一旦找到一个,它就会被加入一个指令列表中,这个列表是用来记录所有和当前DOM相关的指令的。 一旦所有的指令都被确定了,会按照优先级被排序,并且他们的compile方法会被调用。指令的$compile()
函数能修改DOM结构,并且要负责生成一个link函数(后面会提到)。$compile
方法最后返回一个合并起来的链接函数,这是链接函数是每一个指令的compile函数返回的链接函数的集合。大致过程如下:
var $compile = ...; // injected into your code
var scope = ...;
var html = '<div ng-bind='exp'></div>';
// Step 1: parse HTML into DOM element
var template = angular.element(html);
// Step 2: compile the template
var linkFn = $compile(template);
// Step 3: link the compiled template with the scope.
linkFn(scope);
模板之中可能含有指令,指令之中可能又含有模板,模板之中又含有指令,由此形成一棵模板树。只有具有最高优先级的指令中的模板会被编译。如果一个元素已经有一个含有模板的指令了,永远不要对其用另一个指令进行修饰。一个指令会将内部子指令的模板合并在一起成为一个模板函数并返回,它无法查找父指令,只能通过模板函数访问内部子指令
ngModel提供更底层的API来处理控制器内的数据。
ngModel.$setViewValue()
函数,接受一个字符串参数value,表示想要赋予的实际值,然后:ngModel.$setViewValue()
方法会更新控制器本地的$viewValue
,然后将值传递给每一个$parser
函数$parser
所有函数都完成后,值会赋给$modeValue
属性,并且传递给指令中ng-model
属性提供的表达式$viewChangeListeners
中所有的监听器都会被调用单独调用
$setViewValue()
不会唤起一个新的digest循环,因此如果想更新指令,需要在设置$viewValue
后手动触发digest
ngModel的$render
方法可以定义视图具体的渲染方式,它在$parser
完成后被调用
ngModelController中有几个属性可用来检查甚至修改视图: