AnguarJS指令从解析到生效一共会经历Inject、Compile、Controller加载、Pre-link、Post-link这几个主要阶段。

一、AngularJS指令执行过程

  1、加载Angularjs,找到ng-app,确定应用的边界。.将html转换为DOM

  2、遍历DOM,找到所有指令,并编译,执行directive上的complie方法。想在dom渲染前对它进行变形(修改DOM),并且不需要scope参数
想在所有相同directive里共享某些方法,定义在compile里,性能会比较好。编译模板,把表达式{{}}解析成一种特殊的指令:addTextInterpolateDirective。

  3、对每一条指令运行link函数;link函数一般用来操作DOM,绑定事件监听器,监听数据变化,执行directive上的link方法,该方法主要进行scope绑定及事件绑定。对表达式用$watch的API来注册watchers函数

二、通过例子解析生命周期

angular.module('com.ngnice.app').directiveLift('directiveLift',function($log){
  //1、Injecting
$log.info('Injecting function directiveLife');
return {
restrict:'EA',
transclude:true,
replace:true,
template:'<div><h2>count:{{count}}</h2><p ng-transclude></p></div>',
scope:{
count:'='
},
compile:function(elm,iAttrs){
       //2、
$log.info('compile','count value from attribute:'+iAttrs.count);
return {
pre:function(scope,elm, iAttrs){
$log.info('pre-link','count value from attribute:'+iAttrs.count,'count value from scope:'+scope.count);
},
post:function(scope,elm, iAttrs){
$log.info('pre-link','count value from attribute:'+iAttrs.count,'count value from scope:'+scope.count);
}
};
},
controller:function($scope){
$log.info('controller', 'count value from controller:' + $scope.count);
}
};
}); angular.modele('com.ngnice.app').controller('DemoController',function(){
var vm = this,
return vm;
});

  执行结果:

  1、Injecting

    Injecting function directiveLife位置是所有directiveLife指令共享的作用域,可以在这里设置directive默认配置,但是,这类信息有更好的方式进行配置,建议不要这么做,可         以把这类配置信息抽取成Constant,其也是一种全局共享的服务,再注入到指令中,或者在config阶段对默认配置进行定制。其首次解析指令时候执行一次,最多执行一次,如         果不用指令,一次也不执行。

  2、Complie

    接下来执行compile函数,每次实例化指令的时候都调用一次,其有两个参数,原始的Dom元素节点,和它所包含的Attribute的信息,这里传入的DOM节点是初始的DOM节点         没有Link过,虽然在这里可以检查DOM信息和将被执行的表达式,但是不能访问$scope,也不能求出表达式的值,然而,这里是修改节点、插入子模版或兄弟节点的好时机,           稍后,它们就会被Angular自动编译,而不需要我们手动编译它。compile函数最有一句返回后边要用的link函数,包括pre-link和post-link函数。

  3、Controller加载

    在进入Link阶段之前,AngularJS会根据我们在指令中定义Scope,创建独立或非独立的作用域scope,然后,调用指令中的Controller初始化Scope,这里不涉及任何DOM节          点信息,但是我们可以用AngularJS的$injector注入$scope,这里也是唯一能复用的逻辑,不涉及DOM信息,只包含业务逻辑代码。

  3、Link

    Controller初始化指令$scope后,将进入真正的解析过程,分两个阶段:pre-link和post-link,对于指令的每个实例来说也执行一次,对于ngRepeat来说每个item执行一次。因        为在Controller加载阶段已经初始化好$scope对象,所以这里的$scope已经可用,注意的是这里的scope对象是传入的参数,和Controller不同,不是被注入的。此时,每个表达          式都有确定的值,AngularJS开始将模版渲染到DOM。如果想在这里添加模版,已经迟了,AngularJS不会帮忙自动解析,必须手动调用$compile编译、链接它,并插入到指定          DOM中。

  (1)、pre-link

    在plink阶段,pre-link时,子DOM的结构还没有稳定,不适合去添加设计子DOM的行为和监听事件,但是是初始化下级指令需要数据的合适时机。如果下级指令需要得到一          些初始化设置数据,那么应该写在pre-link函数中,我们的最佳实践是在Controller中初始化这类数据,但是如果需要DOM信息才能初始化的情况,只能写在pre-link函数中。

  (2)、post-link

    在指令的开发中,用的最多还是post-link,而不是pre-link,此时,它执行时候,内嵌的指令已经已经被链接过,可以安全的为当前节点或子节点添加某些行为或事件监听函             数,使当前的DOM具有我们期望的能力,自动聚焦或双向绑定。

三、注意点

1、link函数

  (1)、link函数代表的是complie返回的postLink函数;

  (2)、preLink表示在编译阶段之后,在子元素被链接之前执行;

  (3)、postLink会在所有子元素被链接之后执行;

  用link函数创建可以操作DOM的指令。链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义了时,编译函数会重载链接函数。当定义了编译函数来取代链接函数时,链接函数是我们能提供给返回对象的第二个方法,也就是postLink函数。本质上讲,这个事实正说明了链接函数的作用。它会在模板编译并同作用域进行链接后被调用,因此它负责设置事件监听器,监视数据变化和实时的操作DOM。

  

  

注意下:Controller是注入$scope,llink函数是Scope参数对象。

2、控制器和link

  控制器主要是用来提供可在指令间复用的行为,但链接函数只能在当前内部指令中定义行为,且无法在指令间复用.link函数可以将指令互相隔离开来,而controller则定义可复用的行为。

3、编译和链接阶段总结

  编译阶段:

  

  链接阶段:

  

四、例子(compile函数)

var i=0;
angular.module('myApp',[]) //定义第一个指令:customTags
.directive('customTags',function(){
return {
restrict:'ECAM',
template:'<div>{{ user.name }}</div>',
replace:true,
//定义了compile就不需定义link,当compile返回一个方法这个方法就是link
//tElement 正在执行该指令的当前dom元素的jquery对象
//tAttrs 正在执行该指令的当前dom元素的属性
compile:function(tElement,tAttrs,transclude){
//第一个指令的编译阶段...
console.log('customTags compile 编译阶段...'); //若要改变dom元素,应在compile中做,此处在当前dom元素中添加一个<span>
tElement.append(angular.element('<span> {{user.count}}</span>')); return {
//pre:编译阶段之后执行
pre:function preLink(scope,iElement,iAttrs,controller){
console.log('customTags preLink..');
},
//post:所有子元素指令的post都执行后执行,此处设置了dom元素的点击事件
post:function postLink(scope,iElement,iAttrs,controller){ iElement.on('click',function(){
scope.$apply(function(){
scope.user.name=' click after';
scope.user.count= ++i;
});
}); console.log('customTags post end.');
console.log('');
}
}; //compile也可直接返回一个方法,这就是 postLink,也就是上面的post
/*return function (){
console.log('compile return this function')
}*/
},
//进行scope绑定及事件绑定
link:function(scope,iElement,iAttrs,bookListController){
//link不会再执行了,因为这里定义的就是postLink
}
}
})

AngularJS 指令生命周期 complie link的更多相关文章

  1. VUE自定义指令生命周期,VUE生命周期

    一.自定义指令的生命周期 自定义指令有五个生命周期(也叫钩子函数),分别是 bind,inserted,update,componentUpdated,unbind bind:只调用一次,指令第一次绑 ...

  2. vue_实例_组件的生命周期

     重绘重排 中重复出现的是 mounted(){...} beforeUpdate(){...} uptated(){...} 其他钩子函数只会出现一次 <!DOCTYPE html> & ...

  3. Angular4学习笔记(九)- 生命周期钩子简介

    简介 Angular 指令的生命周期,它是用来记录指令从创建.应用及销毁的过程.Angular 提供了一系列与指令生命周期相关的钩子,便于我们监控指令生命周期的变化,并执行相关的操作.Angular ...

  4. angular、angular2、vue的生命周期

    angular生命周期是什么 1.Angular每个组件都存在一个生命周期,从创建,变更到销毁.Angular提供组件生命周期钩子,把这些关键时刻暴露出来,赋予在这些关键结点和组件进行交互的能力,掌握 ...

  5. angular2的生命周期钩子的使用情况

    angular 2 Directive Lifecycleangular2 中组建继承于指令,并扩展了与ui视图相关的属性.angular2 指令的生命周期是用来记录指令从创建,应用及销毁的过程.an ...

  6. angularjs link compile与controller的区别详解,了解angular生命周期

     壹 ❀ 引 我在 angularjs 一篇文章看懂自定义指令directive 一文中简单提及了自定义指令中的link链接函数与compile编译函数,并说到两者具有互斥特性,即同时存在link与c ...

  7. 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive

    ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...

  8. 【转】angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  9. Vue01 Vue介绍、Vue使用、Vue实例的创建、数据绑定、Vue实例的生命周期、差值与表达式、指令与事件、语法糖

    1 Vue介绍 1.1 官方介绍 vue是一个简单小巧的渐进式的技术栈,它提供了Web开发中常用的高级功能:视图和数据的解耦.组件的服用.路由.状态管理.虚拟DOM 说明:简单小巧 -> 压缩后 ...

随机推荐

  1. UISwitch开关控件属性介绍以及获取开关状态并做出响应

    (1)UISwitch的大小也是固定的,不随我们frame设置的大小改变:也是裁剪成圆角的,设置背景就露马脚发现背景是矩形. (2)UISwitch的背景图片设置无效,即我们只能设置颜色,不能用图片当 ...

  2. linux学习第四天 (Linux就该这么学)2018年11月16日

    今天主要讲了 管道符,重写向与环境变量 输入输出重写向 标准输出重写向 (标准,覆盖,错误) > 将标准输出重写向到一个文件中 >> 追加到文件 2>错误输出重定向 2> ...

  3. [RF] 安装好Robot Framework之后怎样让启动的界面后面不带命令行窗口,且图片以机器人显示

    安装好Robot Framework之后,通过 C:\Python27\Scripts\ride.py 启动时会带上一个命令行窗口: 怎样让启动的界面后面不带这个命令行窗口,且图片以机器人显示? 方法 ...

  4. PHP 批量移动文件改名

    public function changeCoverName(){ //$type = '考研'; //$coverPath = './Public/course_cover/kaoyan/'; $ ...

  5. 异常Throwable

    1.有效处理java异常三原则 java中异常提供了一种识别及响应错误情况的一致性机制,有效地异常处理能使程序更加健壮,易于调试.异常之所以是一种强大的调试手段,在于其回答了以下三个问题: 什么出了错 ...

  6. Sliding Window Median LT480

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  7. 第一个spring boot 程序

    安装.运行.预览省略 错误1:8080端口被IIS占用,关闭它 Description: The Tomcat connector configured to listen on port 8080 ...

  8. centos6.5虚拟机每次都要ifup eth0的解决办法

    修改文件/etc/sysconfig/network-scripts/ifcfg-eth0把ONBOOT=no改ONBOOT=yes

  9. Linux学习笔记:系统目录结构

    Linux系统文件夹代表的含义: /bin - Binaries. /boot - Files required for booting. /dev - Device files. /etc - Et ...

  10. 【搜索】 Find The Multiple

    #include<stdio.h> #include<stdlib.h> #include<string.h> bool found; void DFS(unsig ...