angularjs – 为什么ng-repeat改变了链接函数执行的顺序

前端之家收集整理的这篇文章主要介绍了angularjs – 为什么ng-repeat改变了链接函数执行的顺序前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在嵌套指令上执行编译和链接函数的通常顺序如下

标记

<dir1>
  <div dir2="">
  </div>
</dir1>

执行顺序

1) compile of directive 1
2) compile of directive 2
3) link of directive 2
4) link of directive 1

假设dir1将restrict属性设置为’E’,dir2将restrict设置为’A’

现在,如果在同一标记中使用ng-repeat指令,则执行顺序会发生变化

标记

<dir1>
  <div ng-repeat="item in items">
    <div dir2="">
    </div>
  </div>
</dir1>

假设项目是在范围上定义的,执行顺序将更改为

1) compile of directive 1
2) link of directive 1
3) compile of directive 2
4) link of directive 2

Plunker – https://plnkr.co/edit/fRGHS1Bqu3rrY5NW2d97?p=preview

为什么会这样?是因为ng-repeat已将transclude属性设置为element.如果是这种情况,为什么它应该改变dir1的执行顺序,这是在ng-repeat之外.

任何帮助将非常感激.

解决方法

首先,好问题!我曾经使用angular来开发几个webapps,但我从来没有意识到这一点.

这是因为在ngRepeat实施内部,谷歌团队使用了
$scope.$watchCollection监视变量并更新元素.(使用其他一些优化.)通过调用$watchCollection,它调用setTimeout以异步方式评估更改.

然后你可以写下你自己的ngRepeat版本.我们称之为myRepeat.

//mock ng-repeat : )
app.directive('myRepeat',function ($compile) {
    return {
        restrict:'A',transclude: 'element',priority: 1000,terminal: true,$$tlb: true,compile: function ($element,$attr) {
            var expression = $attr.myRepeat;
            var ngRepeatEndComment = $compile.$$createComment('end myRepeat',expression);

            //parse the ngRepeat expressions.
            var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);


            var rhs = match[2]; //this would get items in your example

            return function ($scope,$element,$attr,ctrl,$transclude) {

                //$watch $scope[rhs] which rhs would be items in your example.

                $scope.$watchCollection(rhs,function myRepeatAction(collection) {
                  $transclude(function(clone,scope) {

                    clone[clone.length++] = clone; //append element
                  });

                });   
            }
        }
    }
});

如果注释掉watchCollection语句,您将获得第一个示例的输出.你可以用setTimeout替换$watchCollection来重现相同的日志.

如果我们查看angular.js的源代码,callstack就像watchCollection => $watch => $evalAsync => $browser.defer =>的setTimeout

$watch source code.

$browser.defer source code.

希望这能解决你的问题.

猜你在找的Angularjs相关文章