一. 指令模板选项有complie和link两个字段,两者之间存在如下关系:

  • 当compile字段存在时,link字段将被忽略,compile函数的返回值将作为link字段。
  • 当compile不存在,link字段存在时,angular通过这样directive.compile = valueFn(directive.link);包装一层,使用用户定义的link字段。
  • 当compile和link同事存在时,link被忽略,使用compile函数的返回值将作为link字段,
而link分为preLink和postLink两个阶段,从link字段或者compile函数的返回值来看:
  • 如果是函数,那么这样的link,会被认为是postLink。
  • 如果是对象,那么link.pre作为preLink函数,link.post作为postLink函数 (如下)
app.directive('myDirective', function () {
return {
compile: function () {
return {
pre: function () {
console.log('preLink');
},
post: function () {
console.log('postLink');
}
}
}
}
});

  

angular 启动后,会从ng-app所在元素,递归遍历所有子元素,查找出所有的指令(包括指令模板中的指令),对指令进行编译和连接

编译会执行指令的compile(即使有多个指令实例,compile也只执行一次),·链接会执行指令的link(prelink,postlink)(有多少个指令实例,就执行几次)

二. compile,prelink,postlink的执行顺序

对于一个指令而言,首先会执行compile,然后执行prelink,最后执行postlink

对于所有的指令而言,执行顺序如下

compile的执行顺序

编译过程会按照从外到内(从父到子),从上到下(兄弟节点)以及priority的依次执行所有指令的compile,

prelink和postlink的执行顺序

所有指令的compile都执行完成后,会执行链接过程

链接过程会首先按照从外到内(从父到子)的顺序执行指令的prelink,然后再按照从内到外(从子到父)的顺序执行指令的postlink

从ng-app开始,会依次按照以下顺序执行prelink和postlink

1.如果有子节点指令,那么执行完本节点指令的prelink后,就会执行子节点指令的prelink,

2.如果没有子节点指令,那么会执行完本节点指令的prelink后,就会执行本节点指令的postlink,

3.如果有兄弟节点指令,那么执行完本节点指令的postlink后,就会去执行兄弟节点指令的prelink,

4.如果没有兄弟节点指令,那么执行完本节点指令的postlink后,就会去执行父节点指令的postlink,

以此类推,直到所有的指令的prelink和postlink执行完毕

测试链接:http://plnkr.co/edit/KtMs0H1pBsrOmXrFh9nf?p=preview

事例

html代码

var app = angular.module('plunker', []);

function createDirective(name){
return function(){
return {
restrict: 'E',
controller: function () {
console.log(name + ': controller => ');
},
compile: function(tElem, tAttrs){
console.log(name + ': compile => ' );
return {
pre: function(scope, iElem, iAttrs){
console.log(name + ': pre link => ' );
},
post: function(scope, iElem, iAttrs){
console.log(name + ': post link => ' );
}
}
}
}
}
} app.directive('levelOne', createDirective('levelOne'));
app.directive('levelTwo1', createDirective('levelTwo1'));
app.directive('levelThree1', createDirective('levelThree1'));
app.directive('levelFour1', createDirective('levelFour1'));
app.directive('levelTwo2', createDirective('levelTwo2'));
app.directive('levelThree2', createDirective('levelThree2'));
app.directive('levelFour2', createDirective('levelFour2'));

  

  结果

app.js:11 levelOne: compile =>
app.js:11 levelTwo1: compile =>
app.js:11 levelThree1: compile =>
app.js:11 levelFour1: compile =>
app.js:11 levelTwo2: compile =>
app.js:11 levelThree2: compile =>
app.js:11 levelFour2: compile =>
app.js:8 levelOne: controller =>
app.js:14 levelOne: pre link =>
app.js:8 levelTwo1: controller =>
app.js:14 levelTwo1: pre link =>
app.js:8 levelThree1: controller =>
app.js:14 levelThree1: pre link =>
app.js:17 levelThree1: post link =>
app.js:8 levelFour1: controller =>
app.js:14 levelFour1: pre link =>
app.js:17 levelFour1: post link =>
app.js:17 levelTwo1: post link =>
app.js:8 levelTwo2: controller =>
app.js:14 levelTwo2: pre link =>
app.js:8 levelThree2: controller =>
app.js:14 levelThree2: pre link =>
app.js:17 levelThree2: post link =>
app.js:8 levelFour2: controller =>
app.js:14 levelFour2: pre link =>
app.js:17 levelFour2: post link =>
app.js:17 levelTwo2: post link =>
app.js:17 levelOne: post link =>

  

  

可以看出:
  1. 所有的指令都是先compile,然后preLink,然后postLink。
  2. 节点指令的preLink是在所有子节点指令preLink,postLink之前,所以一般这里就可以通过scope给子节点传递一定的信息。
  3. 节点指令的postLink是在所有子节点指令preLink,postLink完毕之后,也就意味着,当父节点指令执行postLink时,子节点postLink已经都完成了,此时子dom树已经稳定,所以我们大部分dom操作,访问子节点都在这个阶段。
  4. 指令在link的过程,其实是一个深度优先遍历的过程,postLink的执行其实是一个回溯的过程。
  5. 节点上的可能有若干指令,在搜集的时候就会按一定顺序排列(通过byPriority排序),执行的时候,preLinks是正序执行,而postLinks则是倒序执行。

 三. compile,prelink,postlink的作用

Compile 函数

element以及相关的属性是做为参数传递给compile函数的,不过这时候scope是不能用的

使用compile函数可以改变原始的dom(template element),在ng创建原始dom实例以及创建scope实例之前.

可以应用于当需要生成多个element实例,只有一个template element的情况,ng-repeat就是一个最好的例子,它就在是compile函数阶段改变原始的dom生成多个原始dom节点,然后每个又生成element实例.因为compile只会运行一次,所以当你需要生成多个element实例的时候是可以提高性能的.

Pre-link 函数

preLink是在所有子节点指令preLink,postLink之前,所以一般这里就可以通过scope给子节点传递一定的信息.

scope对象以及element实例将会做为参数传递给pre-link函数:

Post-link 函数

postLink是在所有子节点指令preLink,postLink完毕之后,也就意味着,当父节点指令执行postLink时,子节点postLink已经都完成了,

此时子dom树已经稳定,所以我们大部分dom操作,访问子节点都在这个阶段。

可以再次函数做事件的绑定

这就是被认为是最安全以及默认的编写业务逻辑代码的原因.

scope实例以及element实例做为参数传递给post-link函数:

 controller

之前已经讲过compile,prelink 和 postlink的关系,执行顺序,以及作用,这里在追加controller

controler是在compile之后,prelink之前执行,可以在controller中定义一些数据供prelink或postlink使用

或者定义一些方法供其他的指令调用。

可以说controller提供一些外部接口,供其他指令调用,link只处理当前指令。

指令的controller可以通过 指令名+Ctrl 的方式注入到其他指令(指令的第四个参数)

参考: https://blog.csdn.net/qq_28506819/article/details/72598457

angular指令的compile,prelink 和 postlink以及controller的更多相关文章

  1. angular指令中的preLink函数和postLink函数

    指令模板选项有complie和link两个字段,两者之间存在如下关系: 当compile字段存在时,link字段将被忽略,compile函数的返回值将作为link字段. 当compile不存在,lin ...

  2. directive(指令里的)的compile,pre-link,post-link,link,transclude

    The nitty-gritty of compile and link functions inside AngularJS directives  The nitty-gritty of comp ...

  3. Angular1.x directive(指令里的)的compile,pre-link,post-link,link,transclude

    The nitty-gritty of compile and link functions inside AngularJS directives  The nitty-gritty of comp ...

  4. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  5. ng directive compile pre-link post-link

    原文链接: http://www.jb51.net/article/58229.htm 1.ng在link之前编译所有的指令,然后link又分为 pre-link 与 post-link阶段compi ...

  6. angular中的compile和link函数

    angular中的compile和link函数 前言 这篇文章,我们将通过一个实例来了解 Angular 的 directives (指令)是如何处理的.Angular 是如何在 HTML 中找到这些 ...

  7. Angular指令1

    Angular的指令 也就是directive,其实就是一WebComponent,以前端的眼光来看,好象很复杂,但是以后端的眼光来看,还是非常简单的.其实就是一个中等水平的类. var myModu ...

  8. 如何编写Angular指令

    [20140917]Angular:如何编写一个指令 *:first-child { margin-top: 0 !important; } body>*:last-child { margin ...

  9. angular指令之complie和link不得不说的故事

    angular指令比较晦涩难懂的就是complie和link字段了,什么时候该用complie?什么时候该用link?总是很难分别清楚.当理解了指令的真正编译原理的时候,就会发现这相当的简单. ng怎 ...

随机推荐

  1. T-SQL 有参数存储过程的创建与执行

    use StudentManager go if exists(select * from sysobjects where name='usp_ScoreQuery2') drop procedur ...

  2. C# 中使用锁防止多线程冲突

    在编程的时候经常会用到多线程,有时候如果多线程操作同一个资源就会导致冲突,.NET提供了多种方法来防止冲突发生,这里讲下Mutex 该类位于System.Threading命名空间,常用的方式是这样: ...

  3. 如何在ubuntu系统里面用新加装的硬盘对系统进行扩容

    我这里是用256G的固态硬盘安装了系统,想通过扩展1T的机械硬盘存储数据的,现在我们需要的就是把这个1T的硬盘进行扩容进去 使用df -h和sudo fdisk -l命令查看磁盘情况 切换到root用 ...

  4. 深入理解Apache Flink

    Apache Flink(下简称Flink)项目是大数据处理领域最近冉冉升起的一颗新星,其不同于其他大数据项目的诸多特性吸引了越来越多人的关注.本文将深入分析Flink的一些关键技术与特性,希望能够帮 ...

  5. ~Vue实现简单答题功能,主要包含单选框和复选框

    内容 实现简单答题效果 环境 Vue,webpack(自行安装) 实现方式 页面将答题列表传递给调用组件,组件将结果返回给调用页面(其它模式也ok,这只是例子) ------------------- ...

  6. Django中常用命令

    Django 基本命令 熟练使用Django常用命令能让你事半功倍!!!! 1. 新建一个 django project django-admin.py startproject project-na ...

  7. 关于python中生成器之Send方法

    #send主要是用于外部与生成器对象的交互def func1(): # 生成器函数 print("ok1") x = 10 # 函数内局部变量x赋值为10 print(x) x = ...

  8. kafka资料收集

    kafka数据可靠性深度解读  http://blog.csdn.net/u013256816/article/details/71091774 kafka性能调优 http://www.kaimin ...

  9. ROS进阶学习手记 7.2 -- RViz仿真实例2:Create SmartCar

    上一节玩了 exbot 在RViz里的仿真控制,这里我们用urdf文件写个自己的小车模型,ref: http://blog.csdn.net/hcx25909/article/details/8904 ...

  10. CMD定时倒数

    修改if %count%==20 goto finish改变秒数 CMD: mode con: cols=80 lines=25color 4ftitle Please WaitSET /P var= ...