Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2013-01-01) 03. HTML编译器

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

概览

Angular的compiler允许开发者都会浏览器新语法。它能让你把自定义的行为附加(甚至新建)到任何一个HTML元素或属性上。Angularjs把这些行为扩展称为指令(directive)。

HTML有很多声明式的设施用来格式化静态文档的HTML。比如,你想让页面上某个元素在中间显示,你不需要手动计算位置,仅仅添加一个align="center"的属性即可。这就是声明式语言的威力。

但是声明式语言也有很大的限制,因为它不允许你自定义新的语法,只能使用它已经定义好的。比如,你想让浏览器把一段文本放在屏幕的1/3之处,很难实现。所以我们需要一种方式,可以让浏览器学习新的HTML语法。

Angular已经预定义了很多常用的directives,用来帮助创建程序。我们也期待你将会创建与程序相关的指令。这些扩展将变为你创建程序的DSL。

所有这些编译操作都在浏览器中进行,不需要服务器端参与,也不需要预编译过程。

编译器

编译器是一个angular服务,它可以遍历DOM寻找属性。编译过程发生在两个阶段:

  1. Compile: 遍历DOM,并收集所有的指令。结果返回一个linking函数2. Link: 把directives与scope组合起来,产生一些实时动态的视图。当scoe发生变化时,将会反映到view中,当用户操作了view,其变化也会反映到model中。scope model是唯一值得信赖的数据来源。

某些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的人来说,这种方式非常自然。

理解view

市面上有很多模板系统。大多数是把一些静态的文本模板与数据组合起来,产生一个新的文本。然后,把它通过innerHTML放入到一个元素中。

image

这表明数据一旦有变化,就必须重新跟模板结合产生新结果,再次通过innerHTML放入到DOM中。但这么做有很多地方比较麻烦:读取用户输入,与数据结合,覆盖用户输入,管理更新过程,缺乏表达行为的方式等。

Angular不同。Angular通过directives来使用DOM,而不是字符串模板。它的结果是一个将linking函数,将与scope model结合起来产生实时动态的view。view和scope model的绑定是透明的,开发者无须参与即可更新view。因为不需要使用innerHTML,所以不会因为替换数据而丢失用户的输入。还有,angular的directive不仅包含文本绑定,还提供了有与行为相关的结构。(这点难翻)

image

Angular的做法可以产生稳定的DOM。绑定到model示例上的DOM元素,在绑定期间不会改变。这意味着,代码可以持有元素,在上面注册事件处理器,但不必担心在模板数据合并时,这些引用会被破坏。

comments powered by Disqus