AngularJS的指令
一、定义
当我们开发应用程序实现业务需求时都需要扩展HTML,在AngularJS中通过指令来实现。AngularJS 内置了很多常用的指令,也可以根据业务需求自定义指令。
二、指令的执行过程
- 浏览器得到 HTML 字符串内容,解析得到 DOM 结构。
- ng 引入,把 DOM 结构扔给 $compile 函数处理
- 找出 DOM 结构中有变量占位符
- 匹配找出 DOM 中包含的所有指令引用
- 把指令关联到 DOM
- 关联到 DOM 的多个指令按权重排列
- 执行指令中的 compile 函数(改变 DOM 结构,返回 link 函数)
- 得到的所有 link 函数组成一个列表作为 $compile 函数的返回
- 执行 link 函数(连接模板的 scope)
三、内置指令
AngularJS 内置了很多常用的指令,下面简单介绍几个常用的指令。
ng-app
ng-app
指令初始化一个 AngularJS 应用程序。ng-app
指令用于告诉 AngularJS 应用当前这个元素是根元素。所有 AngularJS 应用都必须要要一个根元素。HTML 文档中只允许有一个 ng-app
指令,如果有多个 ng-app
指令,则只有第一个会被使用。
<element ng-app="modulename"> |
|
ng-init
ng-init
指令初始化应用程序数据。
<div ng-app="" ng-init="myText='Hello World!'"> |
ng-model
ng-model
指令把元素值(比如输入域的值)绑定到应用程序。<input>
, <select>
, <textarea>
, 元素支持该指令。
<element ng-model="name"></element> |
<div ng-app="myApp" ng-controller="myCtrl"> |
ng-bind
ng-bind
指令告诉 AngularJS 使用给定的变量或表达式的值来替换 HTML 元素的内容。
如果给定的变量或表达式修改了,指定替换的 HTML 元素也会修改。所有的 HTML 元素都支持该指令。
<element ng-bind="expression"></element> |
或作为 CSS 类:
<element class="ng-bind: expression"></element> |
<div ng-app="" ng-init="myText='Hello World!'"> |
四、自定义指令
除了 AngularJS 内置的指令外,我们还可以创建自定义指令。你可以使用 .directive
函数来添加自定义的指令。要调用自定义指令,HTML 元素上需要添加自定义指令名。
使用驼峰法来命名一个指令, runoobDirective
,但在使用它时需要以 -
分割,runoob-directive
:
<body ng-app="myApp"> |
你可以通过以下方式来调用指令:
- 元素名:
<runoob-directive></runoob-directive>
- 属性:
<div runoob-directive></div>
- 类名:
<div class="runoob-directive"></div>
- 注释:
<!-- directive: runoob-directive -->
1. 指令的属性
- restrict(限制使用)
你可以限制你的指令只能通过特定的方式来调用。通过添加 restrict
属性,并设置只值为 A
, 来设置指令只能通过属性的方式来调用:
var app = angular.module("myApp", []); |
restrict 值可以是以下几种:
E
作为元素名使用A
作为属性使用C
作为类名使用M
作为注释使用
restrict 默认值为 EA
, 即可以通过元素名和属性名来调用指令。
注意:从浏览器的兼容性方面考虑,建议使用A或者E。
- template
模板内容,这个内容会根据replace参数的设置替换节点或只替换节点的内容。
replace
- true :替换节点,会将指令的标签会替换掉
- false(默认值):则把当前指令追加到所在元素内部。
对应 restrict 属性为元素时(E)在最终结果中是多余的,所有replace通常设置为 true。
priority
设置指令在模版中的执行顺序,顺序是相对于元素上其他执行而言,默认为0,从大到小的顺序依次执行。
- terminal
是否以当前指令的权重为结束界限。如果这值设置为 true,则节点中权重小于当前指令的其它指令不会被执行。相同权重的会执行。如如果当前指令的 priority 值为 0, terminal 为true,那么其它priority 值小于0 的指令不会被执行。
- templateUrl
当模板没有定义在指令中时,可以通过templateUrl属性链接外部模板,模板不一定是一个完整的HTML文件。
- scope
指定指令的作用域。
false
指令直接使用父作用域的属性和方法。
true
指令要创建一个新的作用域,这个作用域继承自我们的父作用域(我们修改指令继承过来的属性时,父作用域中对应的属性值不会发生变化)。
{}
创建的一个新的与父作用域隔离的新的作用域,这使我们在不知道外部环境的情况下,就可以正常工作,不依赖外部环境。
var app = angular.module("MyApp", []); |
<div ng-app="MyApp"> |
执行结果:
我们使用了隔离的作用域,不代表我们不可以使用父作用域的属性和方法。我们可以通过向scope
的{}
中传入特殊的前缀标识符(即prefix
)来进行数据的绑定,前缀标识符有如下几种:
@
单项数据绑定标识符
使用方法:在元素中使用属性,如:
<div my-directive my-name="{{name}}"></div> |
注意:属性的名字要用-
将两个单词连接,因为是数据的单项绑定所以要通过使用双大括号来绑定数据。
=
双向数据绑定标识符
使用方法:在元素中使用属性,如:
<div my-directive age="age"></div> |
注意:数据的双向绑定要通过=
前缀标识符实现,所以不可以使用双大括号。
&
绑定函数方法的标识符
使用方法:在元素中使用属性,如:
<div my-directive change-my-age="changeAge()"></div> |
注意:属性的名字要用-
将多个个单词连接。
注意:在新创建指令的作用域对象中,使用属性的名字进行绑定时,要使用驼峰命名标准,比如下面的代码。
scope: { |
controller
他会暴露一个方法其他指令可以注入该方法或者指令(通过指令调用这个方法),利用这个API可以在多个指令之间通过依赖注入进行通信。controllerAs
给controller方法起个别名,方便使用。transclude
设置html页面中使用指令时指定的原始数据在指令内部是否使用,当该属性设置为true时,将指令中的内容渲染到 ng-transclude 指令指定的地方。
如下所示:
var myApp = angular.module('myApp', []) |
<div ng-app="myApp"> |
渲染的结果:
新数据 原始数据 |
- require
填写当前指令需要依赖的其他指令的名称(或者指令名称的字符串数组),并将其控制器作为link函数的第四个参数传入。
选项 | 用法 |
---|---|
directiveName | 通过驼峰法命名法指定指令名称,,Angular将会在自身所提供的指令查找控制器 |
^directiveName | 在上游的指令链中查找所指定的指令中的控制器 |
?directiveName | 表示指令是可选的,如果当前指令中没有找到所需要的控制器,不需要抛出异常 |
2. 指令编译
在angularJs应用启动之前,它们是以HTML文本形式存在文本编辑器当中。应用启动会进行编译和链接,作用域会同HTML进行绑定。
编译阶段(complie):
在编译阶段,AngularJS会遍历整个HTML文档并根据JavaScript中的指令定义来处理页面上声明的指令。当AngularJS调用HTML文档根部的指令时,会遍历其中所有的模板,模板中也可能包含带有模板的指令,一旦对指令和其中的子模板进行遍历或编译,编译后的模板会返回一个叫做模板函数的函数。我们有机会在指令的模板函数被返回前,对编译后的DOM树进行修改。
以下是AngularJS中complie函数的参数:
complie:function(tElement, tAttrs, transclude)
注意事项:
- complie函数用来对模版自身进行转换,仅仅在编译阶段运行一次。
- complie中直接返回的函数是postLink,表示link参数需要执行的函数,也可以返回一个对象里面包含preLink和postLink。
- 当定义complie参数时,将无视link参数,因为complie里返回的就是该指令需要执行的link函数。
链接阶段(link):
链接函数来将模板与作用域链接起来;负责设置事件监听器,监视数据变化和实时的操作DOM.链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义了时,编译函数会重载链接函数。
以下是AngularJS中link函数的参数:
link(scope, iElement, iAttrs, controller)
注意事项:
- link参数代表的是complie返回的postLink。
- preLink 表示在编译阶段之后,指令连接到子元素之前运行。
- postLink 表示会在所有子元素指令都连接之后才运行。
- link函数负责在模型和视图之间进行动态关联,对于每个指令的每个实例,link函数都会执行一次。
var myApp = angular.module('myApp', []); |
<div ng-app="myApp"> |
执行结果如下:
3. 使用实例
以下通过AngularJS指令实现手风琴式的下拉菜单功能,代码如下:
angular.module('myApp', []) |
|
模板文件 kittencupCollapse.html
如下:
<div class="panel panel-default"> |
实现效果:
五、参考博客
- 一招制敌 - 玩转 AngularJS 指令的 Scope (作用域) https://segmentfault.com/a/1190000002773689
- kittencup 的AngularJS教学视频 http://kittencup.com/
- 菜鸟教程AngularJS教程指令章节 http://www.runoob.com/angularjs/angularjs-directives.html