在 AngularJS 中编写指令时,我如何决定是否需要新作用域、新子作用域或新的独立作用域? [英] When writing a directive in AngularJS, how do I decide if I need no new scope, a new child scope, or a new isolated scope?

查看:26
本文介绍了在 AngularJS 中编写指令时,我如何决定是否需要新作用域、新子作用域或新的独立作用域?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一些指导方针,可以用来帮助确定在编写新指令时使用哪种类型的范围.理想情况下,我想要类似于流程图的东西,它会引导我完成一堆问题并弹出正确答案–没有新的新作用域、新的子作用域或新的隔离作用域–但这可能要求太多了.这是我目前的一套微不足道的准则:

I'm looking for some guidelines that one can use to help determine which type of scope to use when writing a new directive. Ideally, I'd like something similar to a flowchart that walks me through a bunch of questions and out pops the correct answer – no new new scope, new child scope, or new isolate scope – but that is likely asking for too much. Here's my current paltry set of guidelines:

  • Don't use an isolated scope if the element that will use the directive uses ng-model
    See Can I use ng-model with isolated scope? and
    Why formatters does not work with isolated scope?
  • If the directive doesn't modify any scope/model properties, don't create a new scope
  • Isolate scopes seem to work well if the directive is encapsulating a set of DOM elements (the documentation says "a complex DOM structure") and the directive will be used as an element, or with no other directives on the same element.

我知道在元素上使用具有隔离作用域的指令会强制同一元素上的所有其他指令使用相同的(一个)隔离作用域,因此这不会严重限制可以使用隔离作用域的时间?

I'm aware that using a directive with an isolated scope on an element forces all other directives on that same element to use the same (one) isolate scope, so doesn't this severely limit when an isolate scope can be used?

我希望 Angular-UI 团队的一些人(或其他编写了许多指令的人)可以分享他们的经验.

I am hoping that some from the Angular-UI team (or others that have written many directives) can share their experiences.

请不要添加简单地说为可重用组件使用隔离范围"的答案.

Please don't add an answer that simply says "use an isolated scope for reusable components".

推荐答案

多好的问题!我很想听听别人怎么说,但这里是我使用的指导方针.

What a great question! I'd love to hear what others have to say, but here are the guidelines I use.

高空前提:作用域是我们用来在父控制器、指令和指令模板之间进行通信的粘合剂".

The high-altitude premise: scope is used as the "glue" that we use to communicate between the parent controller, the directive, and the directive template.

父作用域: 作用域:false,所以根本没有新的作用域

Parent Scope: scope: false, so no new scope at all

我不经常使用它,但正如@MarkRajcok 所说,如果指令不访问任何范围变量(并且显然没有设置任何变量!)那么就我而言这很好.这对于在父指令的上下文中使用的子指令也很有帮助(尽管总是有例外)并且没有模板.基本上,任何带有模板的东西都不属于共享范围,因为您本质上是公开该范围以供访问和操作(但我确信这条规则也有例外).

I don't use this very often, but as @MarkRajcok said, if the directive doesn't access any scope variables (and obviously doesn't set any!) then this is just fine as far as I am concerned. This is also helpful for child directives that are only used in the context of the parent directive (though there are always exceptions to this) and that don't have a template. Basically anything with a template doesn't belong sharing a scope, because you are inherently exposing that scope for access and manipulation (but I'm sure there are exceptions to this rule).

例如,我最近创建了一个指令,该指令使用我正在编写的 SVG 库绘制(静态)矢量图形.它 $observe 的两个属性(widthheight)并在其计算中使用这些属性,但它既不设置也不读取任何范围变量,并且具有没有模板.这是不创建另一个作用域的一个很好的用例;我们不需要一个,那何必呢?

As an example, I recently created a directive that draws a (static) vector graphic using an SVG library I'm in the process of writing. It $observes two attributes (width and height) and uses those in its calculations, but it neither sets nor reads any scope variables and has no template. This is a good use case for not creating another scope; we don't need one, so why bother?

但是,在另一个 SVG 指令中,我需要使用一组数据,另外还必须存储一点状态.在这种情况下,使用父作用域是不负责任的(同样,一般来说).所以相反...

But in another SVG directive, however, I required a set of data to use and additionally had to store a tiny bit of state. In this case, using the parent scope would be irresponsible (again, generally speaking). So instead...

子作用域: 作用域:true

具有子作用域的指令是上下文感知的,旨在与当前作用域进行交互.

Directives with a child scope are context-aware and are intended to interact with the current scope.

显然,与隔离范围相比,它的一个关键优势是用户可以自由地对他们想要的任何属性使用插值;例如在具有隔离作用域的指令上使用 class="item-type-{{item.type}}" 默认情况下将不起作用,但在具有子作用域的指令上运行良好,因为插入的任何内容都可以默认情况下仍可在父作用域中找到.此外,指令本身可以在其自身作用域的上下文中安全地评估属性和表达式,而无需担心对父级的污染或损坏.

Obviously, a key advantage of this over an isolate scope is that the user is free to use interpolation on any attributes they want; e.g. using class="item-type-{{item.type}}" on a directive with an isolate scope will not work by default, but works fine on one with a child scope because whatever is interpolated can still by default be found in the parent scope. Also, the directive itself can safely evaluate attributes and expressions in the context of its own scope without worrying about pollution in or damage to the parent.

例如,工具提示是刚刚添加的内容;隔离范围将不起作用(默认情况下,请参见下文),因为预计我们将在此处使用其他指令或内插属性.工具提示只是一个增强.但是工具提示还需要在作用域上设置一些东西以与子指令和/或模板一起使用,并且显然要管理自己的状态,因此使用父作用域确实很糟糕.我们要么污染它,要么破坏它,布埃诺也不是.

For example, a tooltip is something that just gets added; an isolate scope wouldn't work (by default, see below) because it is expected that we will use other directives or interpolated attributes here. The tooltip is just an enhancement. But the tooltip also needs to set some things on the scope to use with a sub-directive and/or template and obviously to manage its own state, so it would be quite bad indeed to use the parent scope. We are either polluting it or damaging it, and neither is bueno.

我发现自己使用子作用域的频率高于隔离或父作用域.

I find myself using child scopes more often than isolate or parent scopes.

隔离作用域: 作用域:{}

这是用于可重复使用的组件.:-)

This is for reusable components. :-)

但说真的,我认为可重用组件"是自包含组件".其意图是将它们用于特定目的,因此将它们与其他指令结合或向 DOM 节点添加其他内插属性本身没有意义.

But seriously, I think of "reusable components" as "self-contained components". The intent is that they are to be used for a specific purpose, so combining them with other directives or adding other interpolated attributes to the DOM node inherently doesn't make sense.

更具体地说,此独立功能所需的任何内容都通过在父作用域上下文中评估的指定属性提供;它们可以是单向字符串 ('@')、单向表达式 ('&') 或双向变量绑定 ('=').

To be more specific, anything needed for this standalone functionality is provided through specified attributes evaluated in the context of the parent scope; they are either one-way strings ('@'), one-way expressions ('&'), or two-way variable bindings ('=').

在自包含组件上,需要对其应用其他指令或属性是没有意义的,因为它本身就存在.它的样式由它自己的模板控制(如果需要),并且可以嵌入适当的内容(如果需要).它是独立的,所以我们把它放在一个隔离的范围内,也想说:别惹这个.我通过这几个属性给你一个定义的 API."

On self-contained components, it doesn't make sense to need to apply other directives or attributes on it because it exists by itself. Its style is governed by its own template (if necessary) and can have the appropriate content transcluded (if necessary). It's standalone, so we put it in an isolate scope also to say: "Don't mess with this. I'm giving you a defined API through these few attributes."

一个好的最佳实践是从指令链接和控制器函数中尽可能多地排除基于模板的内容.这提供了另一个类似 API"的配置点:指令的用户可以简单地替换模板!功能都保持不变,它的内部 API 从未被触及,但我们可以根据需要尽可能多地处理样式和 DOM 实现.ui/bootstrap 是一个很好的例子,说明如何做好这件事,因为 Peter &帕维尔棒极了.

A good best practice is to exclude as much template-based stuff from the directive link and controller functions as possible. This provides another "API-like" configuration point: the user of the directive can simply replace the template! The functionality all stayed the same, and its internal API was never touched, but we can mess with styling and DOM implementation as much as we need to. ui/bootstrap is a great example of how to do this well because Peter & Pawel are awesome.

隔离范围也非常适合与嵌入一起使用.取标签;它们不仅是整个功能,而且里面的任何内容都可以在父范围内自由评估,同时让选项卡(和窗格)做任何他们想做的事情.选项卡显然有自己的状态,属于范围(与模板交互),但该状态与使用它的上下文无关 - 它完全是内部的制表指令制表指令.此外,将任何其他指令与选项卡一起使用没有多大意义.它们是标签 - 我们已经获得了该功能!

Isolate scopes are also great for use with transclusion. Take tabs; they are not only the whole functionality, but whatever is inside of it can be evaluated freely from within the parent scope while leaving the tabs (and panes) to do whatever they want. The tabs clearly have their own state, which belongs on the scope (to interact with the template), but that state has nothing to do with the context in which it was used - it's entirely internal to what makes a tab directive a tab directive. Further, it doesn't make much sense to use any other directives with the tabs. They're tabs - and we already got that functionality!

用更多的功能包围它或嵌入更多的功能,但指令是它已经是什么.

Surround it with more functionality or transclude more functionality, but the directive is what it is already.

综上所述,我应该注意到,正如@ProLoser 在他的回答中所暗示的那样,有一些方法可以解决隔离范围的一些限制(即功能).例如,在子作用域部分,我提到了在使用隔离作用域(默认情况下)时对非指令属性破坏的插值.但是,例如,用户可以简单地使用 class="item-type-{{$parent.item.type}}" 并且它会再次起作用.因此,如果有一个令人信服的理由在子作用域上使用隔离作用域,但您担心其中的一些限制,请知道如果需要,您几乎可以解决所有这些限制.

All that said, I should note that there are ways around some of the limitations (i.e. features) of an isolate scope, as @ProLoser hinted at in his answer. For example, in the child scope section, I mentioned interpolation on non-directive attributes breaking when using an isolate scope (by default). But the user could, for example, simply use class="item-type-{{$parent.item.type}}" and it would once again work. So if there is a compelling reason to use an isolate scope over a child scope but you're worried about some of these limitations, know that you can work around virtually all of them if you need to.

总结

没有新作用域的指令是只读的;他们是完全信任的(即应用程序内部的)并且他们不接触插孔.具有子作用域的指令添加功能,但它们不是唯一功能.最后,隔离范围用于作为整个目标的指令;它们是独立的,所以让它们流氓是可以的(也是最正确的").

Directives with no new scope are read-only; they're completely trusted (i.e. internal to the app) and they don't touch jack. Directives with a child scope add functionality, but they are not the only functionality. Lastly, isolate scopes are for directives that are the entire goal; they are standalone, so it's okay (and most "correct") to let them go rogue.

我想把我最初的想法说出来,但当我想到更多的事情时,我会更新这个.但是,我的废话 - 这对于一个 SO 答案来说太久了......

I wanted to get my initial thoughts out, but as I think of more things, I'll update this. But holy crap - this is long for an SO answer...

PS:完全切线,但既然我们在谈论范围,我更喜欢说原型",而其他人则更喜欢原型",这似乎更准确,但只是从舌头上滚下来一点也不好.:-)

PS: Totally tangential, but since we're talking about scopes, I prefer to say "prototypical" whereas others prefer "prototypal", which seems to be more accurate but just rolls off the tongue not at all well. :-)

这篇关于在 AngularJS 中编写指令时,我如何决定是否需要新作用域、新子作用域或新的独立作用域?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆