zoukankan      html  css  js  c++  java
  • AngularJS 指令生命周期 complie link

      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  
                }  
            }  
        })  
      
  • 相关阅读:
    VS2005 Web安装程序 创建程序菜单组
    文件夹 文件 加入/去除 Everyone全控
    [转]asp.net 部署数据库、开始菜单、桌面快捷方式实例
    身边的贵人
    AppCode下的cs类 取得相关路径
    遭遇“windows已经阻止此软件因为无法验证发行者”
    成功不是忽悠
    关于 软件注册授权 防止被大面积免费扩散 的设想
    [转]获取机器的硬件信息(CPU ID序列号, 主板信息,硬盘序列号,系统信息)
    递交辞呈之后
  • 原文地址:https://www.cnblogs.com/shawnhu/p/8508724.html
Copyright © 2011-2022 走看看