Angular开发者手册重点翻译之指令(一)文本和属性绑定ngAttr属性绑定

创建自定义的指令

这个文章将解释什么需要在自己的angularjs应用中创建自己的指令,以及如何实现它。

什么是指令

在高的层面上讲,指令是DOM元素中的标记(例如一个属性,一个节点名,注释或者CSS类),它告诉angularjs编译器去给这个元素附加一个指令的行为或者转换DOM元素和它的子元素。

Angularjs拥有一些内建的指令,像ngBind、ngModel和ngClass。非常类似于你创建自己的controller和service,你可以创建你自己的指令个angularjs使用,党angular初始化启动你的应用程序,html编译器将遍历你的DOM元素并且去匹配指令。

匹配指令

在你可以编写指令之前,你需要知道当你使用一个给定的指令的时候,angularjs的html编译器是怎样工作的.

在下面的例子里,我们说<input>元素匹配了ngModel指令:

<input&nbsp;ng-model="foo">

下面的例子也同样匹配ngModel指令:

<input&nbsp;data-ng:model="foo">

Angular规范是一个元素标签和属性名去决定哪个元素匹配哪个指令,我们通常使用大小写敏感的驼峰式规范化命名应用指令。可是因为HTML是大小写不敏感的,所以我们在DOM中使用小写的方式去引用指令,通常在DOM元素上使用短划线分隔的属性。

规范化的形式如下所示:

1:去除元素或者属性以x-和data-的开头。

2:使用:/_/-分隔驼峰式的命名。

例如,以下的格式都是等价的并且匹配ngBind指令:

<div&nbsp;ng-controller="Controller">
  Hello <input&nbsp;ng-model='name'> <hr/>
  <span&nbsp;ng-bind="name"></span> <br/>
  <span&nbsp;ng:bind="name"></span> <br/>
  <span&nbsp;ng_bind="name"></span> <br/>
  <span&nbsp;data-ng-bind="name"></span> <br/>
  <span&nbsp;x-ng-bind="name"></span> <br/>
</div>

最佳实践:推荐使用短划线间隔的格式(比如ngBind指令使用ng-bind),假如你想使用一个HTML验证工具,你可以换为使用data-前缀的样式(比如ngBind指令使用data-ng-bind)。其他的样式,在一些遗留的因素上也是可接受的,但是我们建议你避免使用它们

所有Angular提供的指令匹配属性名、标签名、注释或者类名,下面演示了一个指令可以被引用的几种方式:

<my-dir></my-dir>
<span&nbsp;my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span&nbsp;class="my-dir: exp;"></span>

最佳实践:对比注释和类型,我们更多的倾向于使用标签名和属性,这样可以更容易地确定哪个指令是元素需要去匹配的。

最佳实践:注释形的指令通常用于DOM API不可以跨越多个元素去创建指令的限制(比如在table元素内部),AngularJS 1.2加入了ng-repeat-start和ng-repeat-end作为这个问题的一个更好的解决方案,开发人员被鼓励使用这种方式来替换注释形的指令。

文本和属性绑定

在编译工作阶段,编译器使用$interpolate服务匹配文本和属性,它将发现他们是否包含嵌入的表达式。这些表达式将被注册为watchs,并且作为一个通常的生命周期的一部分被更新,下面是一个interpolation的示例:

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

ngAttr属性绑定

浏览器对属性是否合法经常是挑刺的,例如,考虑一下这个例子:

<svg>
  <circle&nbsp;cx="{{cx}}"></circle>
</svg>

我们期望Angular可以去绑定它,但是当我们查看控制台,我们将会看到一些这样的信息

Error: Invalid value for attribute cx="{{cx}}"

因为SVG DOM API是严谨话的,你不可以简单的写cx="{{cx}}"这样的属性。但是你可以使用ng-attr-cx来绕过这个问题,加入有一个拥有绑定的属性是拥有ngAttr前缀的,在绑定阶段,它将会被应用到相应的无前缀的属性上,这样就允许你去绑定你想要的属性,否则你只能看着它被浏览器处理掉,当使用ngAttr的时候,$interpolate的allOrNothing标识被使用,所以假如任何表达式返回的是undefined,这个属性将会被移除而不是添加到元素上。例如,我们可以像这样修复上文中的问题

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

假如想要去使用一个驼峰式属性名,像viewBox,可以使用下划线去指示属性去绑定到一个实际的驼峰属性上。例如下文中绑定一个viewBox,我们可以这样写:

<svg&nbsp;ng-attr-view_box="{{viewBox}}">
</svg>

创建指令

首先让我们谈谈注册指令的API,与controller相似,指令是注册在module上的,想要注册它,你可以使用module.directive   API,module.directive需要一个规范化的指令名跟随着一个工厂方法,这个工厂方法需要返回一个包含不同选项来告诉$compile指令在被匹配的时候应该怎样去表现的对象。

这个工厂方法只会被在编译器匹配到指令的第一次的时候调用一次,你可以在这个时机执行任何的初始化工作,这个方法需要被$compile.invoke调用使得它可以像controller一样是可注入的。

最佳实践:推荐使用定义对象而不是返回一个方法。

我们将会使用一些指令的通常示例,然后进行深入的探讨不同的选项和编译过程。

最佳实践:为了避免与将来的标准冲突,最好为你自己的指令加一个前缀,比如,加入你想创建一个carousel指令,如果HTML7包含了一个这样的元素,这就会有问题了,两个或者三个字母的前缀就会使它工作的很好,同样的,不要给自己的指令加上ng或者可能会和未来版本的angular引起冲突的前缀。

未完待续…

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端布道

JavaScript设计模式与开发实践 - 高阶函数的应用

定义 高阶函数是指至少满足下列条件之一的函数: 函数可以作为参数被传递; 函数可以作为返回值输出。 JavaScript语言中的函数显然满足高阶函数的条件,在实...

3073
来自专栏PHP技术

PHP 简短而安全的数组遍历

但是其实这样会引起一个重要的问题:如果 $definition['keys'] 没有定义的话,这个时候的数组变量(也就是 foreach)就会出现错误。

942
来自专栏嵌入式程序猿

号外号外:无规矩不成方圆(4)

本文MISRA规则由嵌入式程序猿整理自网络,版权归原作者所有 不能使用三字母词 三字母词由2 个问号序列后跟1 个确定字符组成(如, ??- 代表“ ~”(非)...

2555
来自专栏码洞

跋山涉水 —— 深入 Redis 字典遍历

Redis 字典的遍历过程逻辑比较复杂,互联网上对这一块的分析讲解非常少。我也花了不少时间对源码的细节进行了整理,将我个人对字典遍历逻辑的理解呈现给各位读者。也...

471
来自专栏游戏开发那些事

【游戏开发】小白学Lua(上)

  在很多游戏中,脚本语言是不可或缺的一部分,很多游戏都使用到了Lua,js,python一类的脚本,脚本语言可以在很多方面给开发进程带来帮助。脚本语言可以作为...

782
来自专栏程序员互动联盟

【答疑解惑】常量字符串引发的“血案”

有朋友在《程序员互动联盟》QQ群里问了如下一个问题,见下的QQ截图图: ? 上图与下面这个图中,请注意main函数中s1和s2这两个变量。一个定义为指针,一个定...

3277
来自专栏我是攻城师

Scala里面如何使用break和continue

2423
来自专栏CRPER折腾记

Typescript 2+迷你书 :从入门到不放弃

众所周知:JS中有这么几种类型的数据: Symbol,boolean,Number,Object[Array在js中也属于对象],undefind,null,S...

671
来自专栏Modeng的专栏

Javascript数组系列二之你不了解的迭代1

我们在《Javascript数组系列一之栈与队列》中介绍了一些数组的用法。比如:数组如何表现的和「栈」一样,用什么方法表现的和「队列」一样等等一些方法,因为 J...

1234
来自专栏老司机的技术博客

宝宝都能学会的python编程教程3:字符串和编码

字符串 在python3中已经全面支持中文。 由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为...

2948

扫码关注云+社区