【问题标题】:Angularjs: understanding a recursive directiveAngularjs:理解递归指令
【发布时间】:2013-10-04 10:09:03
【问题描述】:

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

我一直试图通过其他几个 SO 问题来了解它的功能,1,2。我不太明白渲染树指令的递归调用是如何工作的。主要是编译函数

  1. 什么时候调用所有的编译函数?
  2. $compile 函数何时缓存在变量compiledContents 中(这是链接函数吗?),何时追加?为什么不总是追加?

--

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); 
                });
            };
        },

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    Ng 网站有一些很棒的文档(我认为其中一些是最好的)。启动和运行时循环的概述非常有帮助: http://docs.angularjs.org/guide/concepts

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

    执行链接函数,链接范围和指令并生成视图。这可能包括 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/

    【讨论】:

    • 漂亮的例子,但我不得不说,如果这是 Angular 所能做的最好的事情,那么这是实现简单递归结构的一种疯狂方式。
    • 在这个例子中,在指令中添加链接函数会破坏进程吗?我无法让它工作
    • 如果我修改上面的 jsfiddle 以延迟设置范围变量(模拟从 $http.get() 调用中获取数据),它不会获取更改。当数据更新时,你会修改谁来正确重建树?
    • 强烈建议不要使用递归角度指令,因为这将是一个巨大的性能问题。在每次递归调用中,DOM 会自动变深,而渲染深层 DOM 在性能方面会变得非常昂贵
    猜你喜欢
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    相关资源
    最近更新 更多