在嵌套指令上执行编译和链接函数的通常顺序如下
<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
希望这能解决你的问题.