AngularJS创建自定义指令的方法详解

这是一篇译文,来自angular开发者说明的指令。主要面向已经熟悉angular开发基础的开发者。这篇文档解释了什么情况下需要创建自己的指令,和如何去创建指令。

什么是指令

从一个高的层面来讲,指令是angular $compile服务的说明,当特定的标签(属性,元素名,或者注释) 出现在DOM中的时候,它让编译器附加指定的行为到DOM上。

这个过程是很简单的。angular内部有很用这样自带的指令,比如说ngBind, ngView,就像你创建控制器和服务一样,你也可以创建自己的指令。当angular启动的时候,Angular的编译器分析html去匹配指令,这允许指令注册行为或者改变DOM。

匹配指令

在写指令之前,我们首先需要知道的是angular是如何匹配到一个指令的,在以下的例子我们说input元素匹配到ngModel指令.

<input ng-model="foo">

下面这种方法同样也会匹配到ngModel:

<input data-ng:model="foo">

Angular会规范化一个元素的标签名和属性名,以便确定哪一个元素匹配到哪一个指令。我们在js中是通过使用规范化后的驼峰式的名字来引用指令(比如ngModel)。在HTML中常常使用'-'划定的属性名字来调用指令(比如说ng-model).

规范化的处理过程:

-去掉元素或属性上面的x-和data-的前缀
-转化':','-'和‘_-'形式的命名为驼峰式拼写

以下例子展示了用不同的方式匹配到ngBind指令

<span ng-bind="name"></span> <br/> <span ng:bind="name"></span> <br/> <span ng_bind="name"></span> <br/> <span data-ng-bind="name"></span> <br/> <span x-ng-bind="name"></span> <br/>

Best Practice: 优先使用'-'格式的命名(比如说ng-bind匹配ngBind)。如果你想在HTML验证工具中通过,你可以用'data-'前缀的方式(比如data-ng-bind)。其他格式的命名是因为历史遗留的原因存在,避免使用它们。

$compile服务可以基于元素的名字,属性名,类名,和注释来匹配指令

所有Angular内部提供的指令都匹配属性名,标签名,注释,或者类名。以下不同的方式都可以被解析到

<my-dir></my-dir> <span my-dir="exp"></span> <!-- directive: my-dir exp --> <span></span>

Best Practice: 优先利用标签名和属性名的方式使用指令。这样子更容易理解指定的元素匹配到了哪个元素。

Best Practice: 注释的方式通常被用在DOM API限制创建跨越多个元素的指令,比如说table元素,限制重复嵌套,这样就要用注释的方式。在AngularJS 1.2版本中,通过使用ng-repeat-start 和 ng-repeat-end 作为一个更好的方案来解决这个问题。在可能的情况下,推荐使用这种方式。

文本和属性的绑定

在编译过程中,编译器会使用$interpolate服务来检测匹配到的文本和属性值是否包含内嵌表达式。这些表达式被注册为watches,可以在digest循环时被更新。

<a ng-href="img/{{username}}.jpg">Hello {{username}}!</a>

ngAttr属性的绑定

浏览器有些时候会对它认为合法的属性值非常的挑剔(就是某些元素的属性是不可以任意赋值的,否则会报错)。

比如:

<svg> <circle cx="{{cx}}"></circle> </svg>

使用这样的写法时,我们会发现控制台中报错Error: Invalid value for attribute cx="{{cx}}". .这是由于SVG DOM API的限制,你不能简单的写为cx="{{cx}}".

使用ng-attr-cx 可以解决这个问题

如果一个绑定的属性使用ngAttr前缀(或者ng-attr), 那么在绑定的时候将会被应用到相应的未前缀化的属性,这种方式允许你绑定到需要马上被浏览器处理的属性上面(比如SVG元素的circle[cx]属性)。

所以,我们可以这样写来修复以上的问题:

<svg> <circle ng-attr-cx="{{cx}}"></circle> </svg>

创建指令

首先我们来谈论下注册指令的API,跟controller一样,指令是注册在module上,不同的是,指令是通过module.directive API来注册的。module.directive接受的是一个规范化的名字和工厂函数,这个工厂函数返回一个包含不同配置的对象,这个对象用来告诉$compile服务如何进行下一步处理。

工厂函数仅在编译器第一次匹配到指令的时候调用一次。通常在工厂函数中执行初始化的工作。该函数使用$injector.invoke调用,所以它可以像controller一样进行依赖注入。

Best Practice: 优先返回一个定义好的对象,而不是返回一个函数。

接下来,我们先会了解一些常见的例子,然后再深入了解不同的配置项的原理和编译过程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzgwss.html