加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-17 17:26:17 所属栏目:安全 来源:网络整理
导读:在嵌套指令上执行编译和链接函数的通常顺序如下 标记 dir1 div dir2="" /div/dir1 执行顺序 1) compile of directive 12) compile of directive 23) link of directive 24) link of directive 1 假设dir1将restrict属性设置为’E’,dir2将restrict设置为’A
在嵌套指令上执行编译和链接函数的通常顺序如下

标记

<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*([sS]+?)s+ins+([sS]+?)(?:s+ass+([sS]+?))?(?:s+tracks+bys+([sS]+?))?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.

希望这能解决你的问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读