Angularjs:理解递归指令

时间:2013-10-01 20:44:23

标签: javascript angularjs

我在这里找到了一个很棒的树指令。原文:http://jsfiddle.net/n8dPm/

我一直试图通过其他几个问题12来了解它的功能。我无法理解渲染树指令的递归调用是如何工作的。主要是编译功能

  1. 当所有编译函数都调用?
  2. $ compile函数何时缓存在varibale compiledContents中(这是链接函数吗?),何时附加?为什么不总是追加?
  3. -

    compile: function(tElement, tAttr) {
                var contents = tElement.contents().remove();
                var compiledContents;
                return function(scope, iElement, iAttr) {
                    if(!compiledContents) {
                        compiledContents = $compile(contents);
                    }
                    compiledContents(scope, function(clone, scope) {
                             iElement.append(clone); 
                    });
                };
            },
    

1 个答案:

答案 0 :(得分:32)

Ng网站有一些很棒的文档(在我看来是最好的一些)。 Startup和Runtime循环的概述非常有用: http://docs.angularjs.org/guide/concepts

在高级别,当Ng首次启动时,它会从ng-app所在的位置开始编译DOM(被处理为Ng的另一个指令)。这意味着它遍历元素并查看指令和表达式,它需要链接到$ rootScope(所有作用域的根,它们是编译/链接过程设置的原型继承链的一部分)。如果它是一个指令,那么编译过程也在它上面完成。编译过程采用它在HTML中找到的所有Ng指令,并根据指定的优先级对其进行优先级排序,或者假定优先级为零。当它们全部被命令时,它会执行返回链接函数的指令的编译函数。在上面的示例中,有两个show links函数,我将在下面进行注释以及将其链接到此解释的其他注释。 link函数还给出了元素中的HTML,该指令是transclude对象形式的属性,类或元素。

执行链接功能,链接范围和指令以及生成视图。这可能包括HTML / transclude,因此可以添加指令ng-transclude在指令的模板中(其中将使用相同的过程,其模板为transclude)。

以下是我对上面略微更正的自定义指令的说明:

module.directive("tree", function($compile) {
    //Here is the Directive Definition Object being returned 
    //which is one of the two options for creating a custom directive
    //http://docs.angularjs.org/guide/directive
    return {
        restrict: "E",
        //We are stating here the HTML in the element the directive is applied to is going to be given to
        //the template with a ng-transclude directive to be compiled when processing the directive
        transclude: true,
        scope: {family: '='},
        template:       
            '<ul>' + 
                //Here we have one of the ng-transclude directives that will be give the HTML in the 
                //element the directive is applied to
                '<li ng-transclude></li>' +
                '<li ng-repeat="child in family.children">' +
                    //Here is another ng-transclude directive which will be given the same transclude HTML as
                    //above instance
                    //Notice that there is also another directive, 'tree', which is same type of directive this 
                    //template belongs to.  So the directive in the template will handle the ng-transclude 
                    //applied to the div as the transclude for the recursive compile call to the tree 
                    //directive.  The recursion will end when the ng-repeat above has no children to 
                    //walkthrough.  In other words, when we hit a leaf.
                    '<tree family="child"><div ng-transclude></div></tree>' +
                '</li>' +
            '</ul>',
        compile: function(tElement, tAttr, transclude) {
            //We are removing the contents/innerHTML from the element we are going to be applying the 
            //directive to and saving it to adding it below to the $compile call as the template
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {

                if(!compiledContents) {
                    //Get the link function with the contents frome top level template with 
                    //the transclude
                    compiledContents = $compile(contents, transclude);
                }
                //Call the link function to link the given scope and
                //a Clone Attach Function, http://docs.angularjs.org/api/ng.$compile :
                // "Calling the linking function returns the element of the template. 
                //    It is either the original element passed in, 
                //    or the clone of the element if the cloneAttachFn is provided."
                compiledContents(scope, function(clone, scope) {
                        //Appending the cloned template to the instance element, "iElement", 
                        //on which the directive is to used.
                         iElement.append(clone); 
                });
            };
        }
    };
});

整件工作: http://jsfiddle.net/DsvX6/7/