gpt4 book ai didi

angularjs - 将一个指令替换为另一个指令,而无需编译子节点两次

转载 作者:行者123 更新时间:2023-12-02 23:50:06 25 4
gpt4 key购买 nike

在一个项目中,我构建了一个指令 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 的元素有子元素,它们将被编译两次。一次由 Angular 启动的 $compile 函数,一次由我在 aDir 后链接中调用的 $compile 函数。

考虑this plunker 。这是 HTML:

<outer-level>
<p replace-by-another>
<inner-level>Hello World!</inner-level>
</p>
</outer-level>

replaceByAnother 被名为 another 的指令替换。 outerLevelinnerLevel 是指令,除了在调用编译、预链接和后链接函数时登录控制台之外什么也不做。

控制台日志是:

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 的作用以及是否可以避免这种行为。

我通过在 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的输出。
  • 在链接函数中调用此输出以将模板元素绑定(bind)到范围。
<小时/>
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);
});
}
}
}
}
}

最佳答案

使用terminal: true 和高优先级。 AngularJS 按最高优先级到最低优先级编译指令,因此任何具有较高优先级的指令都会在您的指令之前编译

文档:$compile

function replaceByAnother($compile){
return {
restrict: 'A',
terminal: true,
priority: 1000000,
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);
}
}
}
}
}

关于angularjs - 将一个指令替换为另一个指令,而无需编译子节点两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35656800/

25 4 0
文章推荐: angularjs - 在标题模板 angularjs 中显示隐藏菜单
文章推荐: javascript - 通过 request.body 将元数据添加到 GridFS 文件
文章推荐: javascript - 如何使
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com