所以替换:在不久的将来会从AngularJS中删除true。我理解为什么,但我认为没有它可以很好地支持AngularJS中开发的某些场景。
我想创建一个如下所示的按钮组件:
<button ng-click="doSomething()" important-model="outerCtrl.theModel">
important text
</button>
这是从一个属性开始的,例如,像这样:
<div my-button-component>
</div>
现在使用替换我得到我想要的东西,但由于它被弃用了我想避免使用它,所以我想也许我可以这样做:
<button my-button-component ng-click="doSomething()" important-model="outerCtrl.theModel">
</button>
让指令插入重要文本&#39;内部。
这个解决方案很奇怪,因为虽然ng-click可以访问指令范围并且可以按预期工作(就像它在指令模板中一样),但是我的组件是一个按钮,可以点击的事实,以及其他任何东西应该在我的组件中定义,而不是在我选择使用它的模板中定义。
另一种选择就是为所有这些提供一个div包装器,由于前端约束,这是不可接受的。
最后一个选择是接受我无法使用指令控制根元素的类型或属性,并以编程方式应用单击侦听器和任何其他行为(例如ng-class)。这对我来说似乎不是一个好的解决方案,尽管到目前为止它可能是最好的。
这不是我第一次觉得你对指令的根元素有多少控制权有问题,我是否在考虑这个错误?
答案 0 :(得分:6)
首先,我不认为替换:在不久的将来会被删除。它已被弃用,但在任何有角度的1.X版本中摆脱它将是一个突破性的变化,所以我认为你好,直到Angular 2.0发布。 Angular 2.0将会破坏更多,所以我不会过分担心如何使现有的应用程序无需替换:true。 2.0可能具有某种等效功能,但将现有应用程序迁移到2.0可能不是您想要做的事情。
然而,假设地回答你的问题:
replace:true会做两件事:
1)它用指令模板替换DOM中的元素。
2)它将DOM中元素的属性与指令模板合并。
(2)实际上是该特征的重要部分,围绕它的边缘情况是Angular团队想要摆脱它的原因。
例如,如果你的元素是:
<div some-directive ng-click="doSomething()"><div>
someDirective有一个模板:
<div ng-click="doSomethingInDirective()"></div>
更换节点后哪个优先?替换的逻辑:true目前正在做出这些决定,并为您解决所有问题。
如果由于某种原因,替换:true从1.X中删除(它不会),你做什么?
答案是你将不得不手动执行替换:true现在做,哪个(简化)是:
1)获取原始元素的属性
2)将原始元素的属性与指令模板合并,跟踪作为指令的属性和非指令的属性,并跟踪每个指令的声明位置(在原始元素或模板中)。 / p>
3)通过编译合并属性指令和指令模板指令来编译指令模板。
4)将作为原始元素一部分的合并属性指令链接到$ parent范围,将所有其他指令链接到指令范围。将指令链接到指令范围
4a)必要时进行转录(transclude:true,模板包括ng-transclude)
5)用完全链接的指令模板替换原始元素。
以下是Github的相关代码:
if (directive.replace) {
replaceDirective = directive;
if (jqLiteIsTextNode(directiveValue)) {
$template = [];
} else {
$template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
}
compileNode = $template[0];
if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
throw $compileMinErr('tplrt',
"Template for directive '{0}' must have exactly one root element. {1}",
directiveName, '');
}
replaceWith(jqCollection, $compileNode, compileNode);
var newTemplateAttrs = {$attr: {}};
// combine directives from the original node and from the template:
// - take the array of directives for this element
// - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
// - collect directives from the template and sort them by priority
// - combine directives as: processed + template + unprocessed
var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
if (newIsolateScopeDirective) {
markDirectivesAsIsolate(templateDirectives);
}
directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
我不会很快出去写你自己的版本。任何需要替换的代码:true也需要Angular 1.X,因此它将受支持。当你准备用Angular 2.0编写一个新的应用程序时,会有另一种(希望更好的)方法来做到这一点。
答案 1 :(得分:2)
听起来你应该在这种情况下使用指令元素,而不是指令属性。
根据guidance from the Angular docs,当您想要创建可重用组件时使用元素,并在想要增强某些内容的行为时使用属性:
在创建控制模板的组件时使用元素。常见的情况是,您为模板的某些部分创建特定于域的语言。使用新功能装饰现有元素时使用属性。
当您使用不带replace: true
的指令元素时,
<my-button-component example-attr="example"></my-button-component>
将输出:
<my-button-component example-attr="example">
<button ng-click="doSomething()" important-model="outerCtrl.theModel">
important text
</button>
</my-button-component>
<my-button-component>
标记对浏览器没有任何意义,因此不会影响文档流或样式。
在指令中,你仍然会吐出相同的<button>
html,你仍然可以访问通过example-attr
等属性传入的值,所以根本没有太大的区别在replace: true
或replace: false
之间。