前言:在AnguarJS应用启动前,它们以纯文本的形式保存在html中,在应用启动后会按照JavaScript脚本中的规则对DOM进行渲染,并且实现与DOM页面数据的双向绑定,在用户进行操作的时候实现实时响应。这个神奇的机制是怎么发生的?
在这个过程中一共有两个阶段,编译阶段和链接阶段
一、编译阶段
遍历html文档,并根据js中指令定义来处理页面上生命的指令。
模板树可能又大又深,一个模板可能有多个指令对其进行修饰,这些指令本身的模板中可能包含其他的指令,但是只有属于最高优先级指令的模板会被解析并添加到模板树中。
建议:将包含模板的指令和添加行为的指令分离开来。如果一个元素已经有了一个含有模板的指令了,永远不要对其用另一个指令进行修饰。只有具有最高优先级的指令中的模板会被编译。
对html进行遍历和编译之后会返回模板函数,在模板函数返回之前,此时DOM树还没有进行数据绑定,对DOM树进行操作只需要较少的性能开销,所以ng-repeat和ng-transclude等会静态渲染DOM。之后会将模板函数传递给链接函数进行数据连接。
二、链接阶段
链接阶段由链接函数负责。链接函数有两个来源,一个是直接定义为link函数,一个是编译函数返回的函数直接作为链接函数。这两种方式是互斥的,并且第二种的优先级更高。如果同时定义了编译函数compile和链接函数link,那么会默认将编译函数返回的函数作为链接函数进行数据绑定。编译函数负责对模板DOM进行转换,链接函数负责将作用域和DOM进行链接。
1、compile函数
编译函数中可以在指令和实时数据放进DOM之前进行DOM操作,可以增加和删除DOM ,但是不能定义事件监听。返回链接函数,在链接函数中可以定义事件监听器。在实际操作中compile很少用到。因为如果指令是被复用的,在这里进行DOM的增加和删除都是不安全的。
2、link函数
链接函数在模板编译并同作用域建立链接后被调用,负责设置事件监听器,监视数据变化和实时的操作DOM
link函数中如果返回值有一个pre函数,这个函数会在子元素被链接之前执行,post函数会在子元素被链接之后执行。
// require 'SomeController',
link: function(scope, element, attrs, SomeController) {
// 在这里操作DOM,可以访问required指定的控制器
}
参数列表:
参数一:指令内部的作用域
参数二:使用该指令的实例元素
参数三:实例的属性列表
参数四:如果require有定义,则参数四指的是require选项定义的控制器。
控制器在所有的指令间共享,因此指令可以将控制器当作通信通道(公共API)。如果设置了 多个require,那么这个参数会是一个由控制器实例组成的数组,而不只是一个单独的控制器。