在一个项目中,我建立了一个指令aDir,该指令在其后链接函数中使用$ compile替换为另一个bDir。它为bDir创建一个“快捷方式”,这很有用,因为bDir有很多参数,我在整个项目中都使用了它。
在我的模板中:
<p>
<button a-dir></button>
</p>
编译在:
<p>
<button b-dir arg1="" arg2="" ... ></button>
</p>
像这样的代码非常有用:
function aDir($compile){
return {
restrict: 'A',
link: function(scope, iElem, iAttrs){
iElem.attr('b-dir', '');
iElem.attr('arg1', '');
iElem.attr('arg2', '');
[...]
iElem.removeAttr('a-dir'); // To avoid infinite loop
$compile(iElem)(scope);
}
}
}
但是,如果应用aDir的元素有子元素,则它们将被编译两次。一次是$compile
由Angular启动的函数,一次是由$compile
函数在Dir后链接中调用。
考虑一下这个矮子。这是HTML:
<outer-level>
<p replace-by-another>
<inner-level>Hello World!</inner-level>
</p>
</outer-level>
replaceByAnother替换为另一个指令。externalLevel和innerLevel是指令,它们的编译,前置和后置链接功能被调用时,除了登录控制台外,什么也不做。
控制台日志为:
outerLevel: compile
replaceByAnother: compile
innerLevel: compile
outerLevel: pre link
replaceByAnother: pre link
innerLevel: pre link
innerLevel: post link
replaceByAnother: post link
another: compile
innerLevel: compile
another: pre link
innerLevel: pre link
innerLevel: post link
another: post link
outerLevel: post link
因此,我们有两次调用innerLevel的compile,pre link和post link函数。就我而言,这完全可以,但是我有兴趣完全了解$compile
它的作用以及是否可以避免这种行为。
我通过在replaceByAnother指令中定义一个编译函数来尝试了几件事,但我只是设法更改了执行顺序,而不是只对一次innerLevel指令进行编译:
http://plnkr.co/edit/ZnBRaskb1WPkRZv36giS
function replaceByAnother($compile){
return {
restrict: 'A',
compile: function(tElem, tAttrs){
console.log('replaceByAnother: compile');
tElem.attr('another', '');
tElem.removeAttr('replace-by-another');
var anotherLinkFunc = $compile(tElem);
return {
pre: function(scope, iElem, iAttrs){
console.log('replaceByAnother: pre link');
},
post: function(scope, iElem, iAttrs){
console.log('replaceByAnother: post link');
anotherLinkFunc(scope);
}
}
}
}
}
结果:
outerLevel: compile
replaceByAnother: compile
another: compile
innerLevel: compile
innerLevel: compile
outerLevel: pre link
replaceByAnother: pre link
innerLevel: pre link
innerLevel: post link
replaceByAnother: post link
another: pre link
innerLevel: pre link
innerLevel: post link
another: post link
outerLevel: post link
你有什么主意吗?
解
有了@georgeawg和@AndrésEsguerra的答案,我找到了一个令人满意的解决方案:
terminal: true
高优先级来防止Angular编译两次子节点。$compile
。存储的输出$compile
。function replaceByAnother($compile){
return {
restrict: 'A',
terminal: true,
priority: 100000,
compile: function(tElem, tAttrs){
tElem.attr('another', '');
tElem.removeAttr('replace-by-another');
var anotherLinkFunc = $compile(tElem);
return {
pre: function(scope, iElem, iAttrs){
// pre link
},
post: function(scope, iElem, iAttrs){
anotherLinkFunc(scope, function cloneAttachedFn(clone) {
iElem.replaceWith(clone);
});
}
}
}
}
}
您可以通过tElem
在编译阶段将其内部清空并清空来避免第一次内部编译。
//replaceByAnother Directive
function replaceByAnother($compile){
return {
restrict: 'A',
compile: function(tElem, tAttrs){
console.log('replaceByAnother: compile');
//clone tElem
var tClone = tElem.clone();
//empty tElem
tElem.empty();
return {
pre: function(scope, iElem, iAttrs){
//console.log('replaceByAnother: pre link');
},
post: function(scope, iElem, iAttrs){
//console.log('replaceByAnother: post link');
//modify and compile cloned elements
tClone.attr('another', '');
tClone.removeAttr('replace-by-another');
var linkFn = $compile(tClone);
linkFn(scope, function transclude(clone) {
iElem.append(clone);
});
}
}
}
}
}
然后在postLink阶段修改和编译克隆的元素。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句