- 如果将使用指令的元素使用ng-model,请勿使用隔离作用域
请参阅我能在隔离作用域中使用ng-model吗?和
为什么格式化程序不适用于隔离作用域? - 如果指令不修改任何作用域/模型属性,请不要创建新作用域
- 如果指令封装一组DOM元素(文档称之为“复杂的DOM结构”),并且该指令将作为元素使用,或者在同一元素上没有其他指令,则隔离作用域似乎很有效。
我希望来自Angular-UI团队(或其他编写多个指令的开发者)能分享他们的经验。
请不要回答“为可重用组件使用隔离作用域”的简单答案。
多好的问题!我非常愿意听取他人的意见,但以下是我使用的指导方针。
高空作业前提:作用域被用作我们在父控制器、指令和指令模板之间进行通信的“粘合剂”。
父级作用域:scope:false
,因此根本没有新的作用域。
我不经常使用这个选项,但正如@MarkRajcok所说,如果指令不访问任何作用域变量(并显然不设置任何作用域变量!),那么在我看来这完全没问题。这对于仅在父指令上下文中使用且没有模板的子指令非常有帮助(虽然总会有例外情况),基本上任何带有模板的内容都不应该共享作用域,因为你固有地将该作用域暴露给了访问和操作(但我相信也有例外情况)。
例如,我最近创建了一个使用我正在编写的SVG库绘制静态矢量图形的指令。它观测两个属性(width
和 height
)并将它们用于计算,但它既不设置也不读取任何作用域变量,也没有模板。这是一个不需要创建另一个作用域的好用例;我们不需要它,所以为什么要麻烦呢?
但在另一个SVG指令中,我需要使用一组数据并额外存储了一点状态。在这种情况下,使用父级作用域是不负责任的(通常情况下同样如此)。因此...
子级作用域:scope: true
带有子级作用域的指令具有上下文感知能力,并旨在与当前作用域进行交互。
显然,与隔离作用域相比的一个关键优势是用户可以自由地在任何想要使用插值的属性上使用它;例如,在具有隔离作用域的指令上使用“class =”item-type- {{item.type}}“将不起作用(默认情况下),但在具有子作用域的指令上可以正常工作,因为无论插值的内容是什么,默认情况下都可以在父作用域中找到。此外,指令本身可以安全地在其自己的作用域中评估属性和表达式,而不必担心污染或损坏父作用域。scope: {}
这是为可重用组件设计的。 :-)class="item-type-{{$parent.item.type}}"
,它会再次起作用。因此,如果有充分的理由使用隔离作用域而又担心这些限制中的一些,知道如果需要,您可以绕过几乎所有这些限制。没有新作用域的指令是只读的;它们完全可以信任 (即内部应用程序),并且它们不会影响到其他东西。有子作用域的指令添加功能,但它们并不是唯一的功能。最后,孤立作用域是用于整个目标是指令的情况;它们是独立的,所以让它们变得不受约束是可以的(也是最“正确”的)。
我想先把我最初的想法说出来,但是随着我的思考,我会更新这个想法。不过天啊 - 对于一个SO答案来说,这个问题太长了...
PS:完全离题,但既然我们谈论到作用域,我更喜欢说“原型”而其他人更喜欢“原型式”,尽管它似乎更准确,但发音却不太好听。 :-)
ngInclude
。或者将其作为构建的一部分来完成。有很多选择! - Josh David Miller我想要创建很多作用域方法和变量,这些方法和变量只能被我指令使用,并且从未被用户看到或直接访问。我想要白名单控制哪些作用域数据对我可用。我可以使用传输(transclusion)允许用户跳回到父级作用域(不受影响)。 我不希望在传输的子元素中访问到我的变量和方法。
我想要创建作用域方法和变量,可以被用户访问,但与指令上下文之外的包容作用域(兄弟和父级)无关。同时我也想要所有的父级作用域数据自动向下传递。
我不需要处理作用域方法或变量。我可能正在做一些与作用域无关的事情(比如显示简单的jQuery插件,验证等等)。
ng-model=$parent.myVal
(子级)或ngModel: '='
(隔离)的事情来规避奇怪的行为。require:'^ngModel'
以查找父元素。写了很多指令后,我决定使用较少的 隔离
作用域。虽然它很酷,可以封装数据并确保不会泄漏到父作用域中,但严重限制了您可以一起使用的指令数量。
如果您要编写的指令完全独立运行,不与其他指令共享,请使用 隔离作用域。(像一个组件,您只需将其插入,对最终开发人员没有太多自定义)。 (这在尝试编写其中包含指令的子元素时会变得非常棘手)
如果您要编写的指令只是进行 DOM 操作,不需要作用域内部状态或明确的作用域更改(主要是非常简单的事情);请使用无新作用域。(例如 ngShow
、ngMouseHover
、ngClick
、ngRepeat
)
如果您要编写的指令需要更改父作用域中的某些元素,但也需要处理一些内部状态,请使用 新子作用域。(例如 ngController
)
务必查看指令的源代码:https://github.com/angular/angular.js/tree/master/src/ng/directive,它极大地帮助了解如何思考它们。
ngClick
等好运)。我同意要求创建了一种解耦,但您仍然需要注意父指令。除非它像组件一样,否则我反对采用隔离。指令(至少大多数指令)旨在高度可重用,而隔离会破坏这一点。 - Umur Kontacı我想分享一下我的理解,并将其与其他JS概念联系起来。
默认情况(例如未声明或范围:false)
这在哲学上等同于使用全局变量。指令可以访问父控制器中的所有内容,但同时也会受到影响。
范围:{}
这就像一个模块,它需要显式传递任何要使用的内容。如果您使用的每个指令都是隔离作用域,那么它就相当于使您编写的每个JS文件都成为自己的模块,需要注入所有依赖项。
范围:child
这是全局变量和显式传递之间的折中方案。它类似于JavaScript的原型链,只是扩展了父级作用域的副本。如果创建了隔离作用域并传递了父作用域的每个属性和函数,则在功能上等效于此。
关键是任何指令都可以以任何方式编写。不同的范围声明只是为了帮助您组织代码。您可以使所有内容都成为模块,也可以只使用所有全局变量并非常小心。但出于易于维护的考虑,最好将逻辑模块化为逻辑上相关的部分。在开放式草地和封闭式监狱之间存在平衡。 我认为这很棘手的原因是,当人们了解这一点时,他们认为他们正在学习指令如何工作,但实际上他们正在学习代码/逻辑组织。
另一个帮助我理解指令如何工作的事情是学习ngInclude。 ngInclude可帮助您包含HTML部分。当我开始使用指令时,我发现可以使用其模板选项来减少代码量,但我并没有真正附加任何逻辑。
当然,在Angular的指令和angular-ui团队的工作之间,我还没有必要创建自己的具有实质性功能的指令,因此我对此的看法可能完全错误。
scope: true
将自动创建一个使用$scope.new()
的子作用域。 - Josh David Millerscope: false
(默认值,没有新作用域),scope: true
(新继承原型的作用域),以及scope: { ... }
(新的隔离作用域)。 - Mark Rajcok