Angular的compiler允许开发者都会浏览器新语法。它能让你把自定义的行为附加(甚至新建)到任何一个HTML元素或属性上。Angularjs把这些行为扩展称为指令(directive)。
HTML有很多声明式的设施用来格式化静态文档的HTML。比如,你想让页面上某个元素在中间显示,你不需要手动计算位置,仅仅添加一个align="center"
的属性即可。这就是声明式语言的威力。
但是声明式语言也有很大的限制,因为它不允许你自定义新的语法,只能使用它已经定义好的。比如,你想让浏览器把一段文本放在屏幕的1/3之处,很难实现。所以我们需要一种方式,可以让浏览器学习新的HTML语法。
Angular已经预定义了很多常用的directives,用来帮助创建程序。我们也期待你将会创建与程序相关的指令。这些扩展将变为你创建程序的DSL。
所有这些编译操作都在浏览器中进行,不需要服务器端参与,也不需要预编译过程。
编译器是一个angular服务,它可以遍历DOM寻找属性。编译过程发生在两个阶段:
某些directives例如ng-repeat
会为集合中的每一个元素克隆一遍DOM元素。把编译过程分为compile和link两个阶段,对于性能的提升很有帮助 ,因为克隆的模板仅仅需要编译一次即可(然后link到每一个克隆后的示例)
Directive是指我们添加到HTML代码中,在编译阶段需要特别处理的那些结构性代码。Directive可以放在元素名上,属性上,class名上,甚至注释中。下面是几个调用ng-bind
这个directive的示例:
<span ng-bind="exp"></span>
<span class="ng-bind: exp;"></span>
<ng-bind></ng-bind>
<!-- directive: ng-bind exp -->
可参看directive章节以深入了解如何编写自己的directives。
这里有一个directive,可以让何意一个元素“可拖动“。注意`<span>`上的`draggable`元素。
### 源代码
**index.html**
<span draggable>Drag ME</span>
**script.js**
angular.module('drag', []).
directive('draggable', function($document) {
var startX=0, startY=0, x = 0, y = 0;
return function(scope, element, attr) {
element.css({
position: 'relative',
border: '1px solid red',
backgroundColor: 'lightgrey',
cursor: 'pointer'
});
element.bind('mousedown', function(event) {
startX = event.screenX - x;
startY = event.screenY - y;
$document.bind('mousemove', mousemove);
$document.bind('mouseup', mouseup);
});
function mousemove(event) {
y = event.screenY - startY;
x = event.screenX - startX;
element.css({
top: y + 'px',
left: x + 'px'
});
}
function mouseup() {
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
}
});
任意一个元素添加了draggable
属性后,就有了新的行为。这种方式的美妙之处在于,我们教会了浏览器新的技能,扩展了它所支持词汇,对于熟悉HTML的人来说,这种方式非常自然。
市面上有很多模板系统。大多数是把一些静态的文本模板与数据组合起来,产生一个新的文本。然后,把它通过innerHTML
放入到一个元素中。
这表明数据一旦有变化,就必须重新跟模板结合产生新结果,再次通过innerHTML
放入到DOM中。但这么做有很多地方比较麻烦:读取用户输入,与数据结合,覆盖用户输入,管理更新过程,缺乏表达行为的方式等。
Angular不同。Angular通过directives来使用DOM,而不是字符串模板。它的结果是一个将linking函数,将与scope model结合起来产生实时动态的view。view和scope model的绑定是透明的,开发者无须参与即可更新view。因为不需要使用innerHTML
,所以不会因为替换数据而丢失用户的输入。还有,angular的directive不仅包含文本绑定,还提供了有与行为相关的结构。(这点难翻)
Angular的做法可以产生稳定的DOM。绑定到model示例上的DOM元素,在绑定期间不会改变。这意味着,代码可以持有元素,在上面注册事件处理器,但不必担心在模板数据合并时,这些引用会被破坏。