何时以及如何使用compile,controller,pre

在编写Angular指令时,可以使用以下任何函数来操作DOM行为,声明指令的元素的内容和外观:

  • 调节器
  • 前链路
  • 后链接
  • 对于应该使用哪种功能,似乎存在一些混淆。 这个问题包括:

    指令基础

  • 如何声明各种功能?
  • 源模板和实例模板有什么区别?
  • 指令函数以何种顺序执行?
  • 这些函数调用之间还会发生什么?
  • 功能性,do和dont's

  • 调节器
  • 预链接
  • 帖子链接
  • 相关问题:

  • 指令:链接vs编译与控制器。
  • 定义angular.js指令时,“控制器”,“链接”和“编译”函数之间的区别。
  • angularjs中的编译和链接函数有什么区别。
  • AngularJS指令中的预编译和后编译元素之间的区别?
  • Angular JS指令 - 模板,编译或链接?
  • 发布链接vs Angular js指令中的前链接。

  • 指令函数以何种顺序执行?

    对于单个指令

    基于下面的plunk,请考虑以下HTML标记:

    <body>
        <div log='some-div'></div>
    </body>
    

    通过以下指令声明:

    myApp.directive('log', function() {
    
        return {
            controller: function( $scope, $element, $attrs, $transclude ) {
                console.log( $attrs.log + ' (controller)' );
            },
            compile: function compile( tElement, tAttributes ) {
                console.log( tAttributes.log + ' (compile)'  );
                return {
                    pre: function preLink( scope, element, attributes ) {
                        console.log( attributes.log + ' (pre-link)'  );
                    },
                    post: function postLink( scope, element, attributes ) {
                        console.log( attributes.log + ' (post-link)'  );
                    }
                };
             }
         };  
    
    });
    

    控制台输出将是:

    some-div (compile)
    some-div (controller)
    some-div (pre-link)
    some-div (post-link)
    

    我们可以看到, compile首先执行,然后是controller ,然后是pre-link ,最后是post-link

    对于嵌套指令

    注意:以下内容不适用于呈现其子项链接功能的指令。 不少角指示这样做(如ngIf,ngRepeat,或与任何指令transclude )。 这些指令本来就会在它们的子指令compile被调用之前调用它们的link函数。

    原始的HTML标记通常由嵌套元素组成,每个嵌套元素都有自己的指令。 就像下面的标记一样(参见plunk):

    <body>
        <div log='parent'>
            <div log='..first-child'></div>
            <div log='..second-child'></div>
        </div>
    </body>
    

    控制台输出将如下所示:

    // The compile phase
    parent (compile)
    ..first-child (compile)
    ..second-child (compile)
    
    // The link phase   
    parent (controller)
    parent (pre-link)
    ..first-child (controller)
    ..first-child (pre-link)
    ..first-child (post-link)
    ..second-child (controller)
    ..second-child (pre-link)
    ..second-child (post-link)
    parent (post-link)
    

    我们可以在这里区分两个阶段 - 编译阶段和链接阶段。

    编译阶段

    当DOM被加载时,Angular开始编译阶段,它从上到下遍历标记,并调用所有指令的compile 。 在图形上,我们可以这样表达:

    可能很重要的一点是,在这个阶段,编译功能获取的模板是源模板(不是实例模板)。

    链接阶段

    DOM实例通常只是源模板呈现给DOM的结果,但它们可能是由ng-repeat创建的,或者是实时引入的。

    每当具有指令的元素的新实例呈现给DOM时,链接阶段就开始。

    在这个阶段,Angular调用controllerpre-link ,迭代子代,并在所有指令中调用post-link ,如下所示:

    演示链接阶段步骤的插图


    这些函数调用之间还会发生什么?

    各种指令函数是在两个其他角度函数中执行的,这两个函数称为$compile (其中指令的compile被执行)和一个名为nodeLinkFn (指令的controllerpreLinkpostLink被执行)的内部函数。 在调用指令函数之前和之后,角函数内会发生各种各样的事情。 也许最值得注意的是孩子递归。 下面的简图说明了编译和链接阶段的关键步骤:

    显示Angular编译和链接阶段的插图

    为了演示这些步骤,我们使用下面的HTML标记:

    <div ng-repeat="i in [0,1,2]">
        <my-element>
            <div>Inner content</div>
        </my-element>
    </div>
    

    遵循以下指令:

    myApp.directive( 'myElement', function() {
        return {
            restrict:   'EA',
            transclude: true,
            template:   '<div>{{label}}<div ng-transclude></div></div>'
        }
    });
    

    compile API看起来像这样:

    compile: function compile( tElement, tAttributes ) { ... }
    

    通常这些参数前缀为t来表示所提供的元素和属性是源模板的属性,而不是实例的属性。

    在调用compile transcluded内容(如果有的话)之前,将模板应用于标记。 因此,提供给compile函数的元素将如下所示:

    <my-element>
        <div>
            "{{label}}"
            <div ng-transclude></div>
        </div>
    </my-element>
    

    请注意,此处转录的内容不会重新插入。

    在对指令的.compile进行调用之后,Angular将遍历所有子元素,包括可能刚刚由指令引入的那些元素(例如模板元素)。

    实例创建

    在我们的例子中,将创建上面三个源模板实例(通过ng-repeat )。 因此,下面的序列将执行三次,每个实例一次。

    调节器

    controller API涉及:

    controller: function( $scope, $element, $attrs, $transclude ) { ... }
    

    进入链接阶段后,通过$compile返回的链接函数现在提供了一个范围。

    首先,链接函数根据请求创建一个子范围( scope: true )或一个隔离范围( scope: {...} )。

    然后执行控制器,提供实例元素的作用域。

    预链接

    pre-link API看起来像这样:

    function preLink( scope, element, attributes, controller ) { ... }
    

    事实上,没有任何反应的调用指令的之间.controller.preLink功能。 Angular还提供了如何使用每个应用程序的建议。

    .preLink调用之后,链接函数将遍历每个子元素 - 调用正确的链接函数并将其附加到当前作用域(作为子元素的父作用域)。

    帖子链接

    post-link API与pre-link功能类似:

    function postLink( scope, element, attributes, controller ) { ... }
    

    也许值得注意的是,一旦一个指令的.postLink函数被调用,其所有子元素的链接过程就完成了,包括所有孩子的.postLink函数。

    这意味着在.postLink被调用的时候,孩子们'活着'已经准备好了。 这包括:

  • 数据绑定
  • 应用跨分类
  • 附加范围
  • 这个阶段的模板将如下所示:

    <my-element>
        <div class="ng-binding">
            "{{label}}"
            <div ng-transclude>                
                <div class="ng-scope">Inner content</div>
            </div>
        </div>
    </my-element>
    

    如何声明各种功能?

    编译,控制器,预链接和后链接

    如果要使用全部四个函数,指令将遵循以下形式:

    myApp.directive( 'myDirective', function () {
        return {
            restrict: 'EA',
            controller: function( $scope, $element, $attrs, $transclude ) {
                // Controller code goes here.
            },
            compile: function compile( tElement, tAttributes, transcludeFn ) {
                // Compile code goes here.
                return {
                    pre: function preLink( scope, element, attributes, controller, transcludeFn ) {
                        // Pre-link code goes here
                    },
                    post: function postLink( scope, element, attributes, controller, transcludeFn ) {
                        // Post-link code goes here
                    }
                };
            }
        };  
    });
    

    请注意,compile会返回一个包含前链接和后链接功能的对象; 在Angular术语中,我们说编译函数返回一个模板函数。

    编译,控制器和后链接

    如果不需要pre-link ,那么编译函数可以简单地返回后链接函数而不是定义对象,如下所示:

    myApp.directive( 'myDirective', function () {
        return {
            restrict: 'EA',
            controller: function( $scope, $element, $attrs, $transclude ) {
                // Controller code goes here.
            },
            compile: function compile( tElement, tAttributes, transcludeFn ) {
                // Compile code goes here.
                return function postLink( scope, element, attributes, controller, transcludeFn ) {
                        // Post-link code goes here                 
                };
            }
        };  
    });
    

    有时候,希望在定义(后) link方法之后添加一个compile方法。 为此,可以使用:

    myApp.directive( 'myDirective', function () {
        return {
            restrict: 'EA',
            controller: function( $scope, $element, $attrs, $transclude ) {
                // Controller code goes here.
            },
            compile: function compile( tElement, tAttributes, transcludeFn ) {
                // Compile code goes here.
    
                return this.link;
            },
            link: function( scope, element, attributes, controller, transcludeFn ) {
                // Post-link code goes here
            }
    
        };  
    });
    

    控制器和后链接

    如果不需要编译函数,则可以完全跳过它的声明并在指令的配置对象的link属性下提供后链接功能:

    myApp.directive( 'myDirective', function () {
        return {
            restrict: 'EA',
            controller: function( $scope, $element, $attrs, $transclude ) {
                // Controller code goes here.
            },
            link: function postLink( scope, element, attributes, controller, transcludeFn ) {
                    // Post-link code goes here                 
            },          
        };  
    });
    

    没有控制器

    在上述任何一个示例中,如果不需要,可以简单地删除controller功能。 因此,例如,如果仅需要post-link功能,则可以使用:

    myApp.directive( 'myDirective', function () {
        return {
            restrict: 'EA',
            link: function postLink( scope, element, attributes, controller, transcludeFn ) {
                    // Post-link code goes here                 
            },          
        };  
    });
    
    链接地址: http://www.djcxy.com/p/77905.html

    上一篇: when and how to use compile, controller, pre

    下一篇: Difference between the 'controller', 'link' and 'compile' functions when defining a directive