如何在单页面应用(SPA)中实现清洁的 ID 空间?常见解决方案有哪些?

11
情况:几个开发人员在不同的SPA部分/模块上远程工作。因此,他们可能会意外地引入具有相同id的HTML元素。在最终组装之前,避免这种情况的常见方法是什么(如果可能,不要拒绝使用id)?
我肤浅的猜测:
- 为所有名称预先安排id (有点荒谬但...) - 使用架构结构化名称,例如为app/collection/model专门指定一个名称,如app-collection-model - 拒绝总体上使用id,或仅用于大模块?
注意:保留了原文中的HTML标签。

2
SPA - 单页应用程序 - anthony sottile
2
我认为团队之间的交流是更好的方式。 - felipekm
不要为任何事情使用ID。 - PW Kad
目前我正在开发一个庞大的SPA,我们决定使用包名+“普通”名称作为ID。 - GuyT
最正确的答案是测试和持续集成,例如http://stridercd.com/,其余的则取决于个人偏好,并鼓励少使用ID。确实,名称很重要,但约定只是良好组织的一部分,它并不是万无一失的。 - Dylan
7个回答

3
尽量避免使用 ID,除非绝对必要。在从 CSS 或 JS 引用 HTML 片段时,应该使用类而不是 ID。你的 CSS 和 JS 不应该真正关心 DOM 的确切结构或页面上有多少“foo”元素...它们只想样式化或操作存在的任何“foo”元素,而类完全适合。
当然,你无法完全避免使用 ID...例如,标记你的 HTML 以支持辅助功能将需要使用 ID...但这些 ID 及其引用将受限于同一 HTML 文件(或 SPA 模板),因此如果你觉得可能会出现冲突,请让它们冗长以避免冲突。
当然,这并不能完全解决你的问题。通过专注于类,你避免了生成无效 HTML 并导致所有东西崩溃的可能性,但仍然存在协作问题,需要确保人们不会意外地通过使用相同的类名来弄乱彼此的工作。在许多情况下,你实际上希望在页面之间使用相同的类。然而,在你想确保没有冲突的情况下(例如,在整个站点上具有常见的按钮或排版样式),你可以将每个 HTML 模板包装在类似于 <div class='name-of-this-template'>...</div> 的东西中,然后在你的 CSS/JS 选择器中,将其限定为仅匹配该模板内部:.name-of-this-template .a-class-used-within-the-template

2
注意类名冲突可能会导致的问题。顺便说一句,我通过将容器进行作用域限定(例如,在父包装器上设置类),或者使用带有明确资格的ID,如document-editor-save-button(这需要额外的输入,但可以消除大部分歧义)来解决此问题。如果需要,我还会动态生成ID前缀,并将其添加到元素/元素引用中。这样可以消除所有歧义。 - Tim M.

3
如果您用不同的ID写相同的HTML代码,那么就做错了什么。如今,有许多创建可重用HTML组件的方法,这些组件不需要ID。
我认为有问题的是:对于大型项目(涉及多个团队或大量视图),我认为重复编写原始HTML代码不是一个好主意。这种方法意味着:代码重复和以后重构的痛苦(考虑2年后应用程序的重新设计)。这就是为什么有这么多UI框架可以帮助创建可重用的组件,其中HTML只需编写一次即可在任何地方使用。最终,您的应用程序将需要几个组件:表格、弹出窗口、表单、子菜单、选项卡等。
目标是创建具有这些组件的框架,开发人员可以使用它们创建视图,而无需实际编写任何HTML代码。
我的观点是:对于大型项目,HTML代码应该只编写一次。显然,编写一次并不意味着它只能在一个位置呈现,它可以出现在应用程序的任何地方。
我的建议是:数据绑定拯救!如果无法进行大规模更改,则按照惯例进行。您提出的那个方法可能是有道理的,但要小心,每次更改结构时,所有ID都将是错误的!

我不能完全同意你的观点。如果你在用不同的ID写相同的HTML代码,那么你可能做错了什么。但这并不总是正确的。如果你有多个屏幕上都有相同字段的情况,你很可能会使用相同的ID(例如:屏幕1:关系,屏幕2:订单...两者都将有一个名为“名称”的字段,很可能具有相同的ID)。 - GuyT
@GuyT,我更新了我的答案以澄清我的想法。如果我没有解释清楚,对不起! - margabit
现在我同意你的看法 :). 在当前项目中,我们甚至不使用HTML(只用JS),而是让DOJO来完成标记。 - GuyT
没错!这就是重用组件的好处,将 UI 问题集中到一个地方。 - margabit
另一个事实是更容易向客户销售。您可以使用这个论点,即他们可以毫无问题地转换到另一个框架 ;) - GuyT
@margabit 我遇到的自动生成ID的问题是,它们很难编写自动化单元测试。例如,如果有许多具有相同命名约定的ID部分,则在尝试在自动化测试中断言部分时可能会导致困难。这就是为什么我尽量鼓励使用明智的名称(请注意,我并不是说惯例不好,只是根据我的经验,它们可能会引起问题!) - Ben Smith

2
在我的一个项目中,我们遇到了这个问题。我们的快速解决方案和下一次代码维护/重构周期的一部分是使用可识别的html元素,继承JavaScript容器的属性与模板。
让我详细说明一下。
我们使用Backbone.Marionette与Handlebars模板。对于每个模板,我们都有一个自定义的View类(我们随着开发的进行扩展了Backbone.Marionette的更多功能)与每个模板相关联。这个View类有一个ID和UI元素。UI元素编译在模板中,因此我们永远不必改变HTML,除非我们在视图类本身中更改UI元素名称。因此,我们可以随意更改UI元素的Id,而不会影响任何内容(几乎)。
由于我们为每个小部件使用视图,所以您可以确保它们的标识符或名称或您想如何称呼它,都是唯一的。我们将其用作UI元素中Id的基础。这允许我们重复使用小部件。
Underscore库中的_.uniqueId()也经常用于CollectionViews。
希望我能帮到你,干杯!

2
如果你的代码(问题)非常庞大,而且你无法重构它,你可以在每次提交之前尝试验证你的CSS/HTML以查找重复的ID。但这只是针对非常糟糕的情况的可能解决方案。
更好的解决方案是使用像BEM(http://bem.info/)这样的工具。

有没有任何文章介绍BEM为什么比其他工具更好? - Nik Terentyev
1
我不使用BEM,但我从中借鉴了一些思想:我只使用长名称类而不使用ID和复杂选择器。这使得我的浏览器性能良好,代码易读且具有树形结构(使用SCSS 3.3 - jsbin.com/vohekupa/2/edit)。这对于BEM、OOCSS等都是适用的。完整的BEM说“将每个小部件放在不同的文件夹中”,以确保在文件系统级别上具有不同的名称。BEM是Yandex(俄罗斯的Google)项目,旨在让成千上万的开发人员共同工作并回答许多问题。它拥有良好的社区和各种工具,但它是一个庞然大物。更多信息请参见:vimeo.com/38346573。 - Aleksey

2

给每个开发者(或模块)分配独特的id前缀。

例如,如果开发者X正在开发模块Y,他的前缀应该是x_y_xy_之一。
假设选择了x_,那么由他创建的ID将看起来像这样:x_foox_barx_thing等。

优点:

  1. 避免冲突的ID(显然)。

  2. 在集成模块时,ID清楚地表明它们属于哪里。
    这提供了更好的可读性,非常棒!

  3. 编写x_something已经足够烦人,以避免过度使用ID。
    同时,它又不会让人烦到完全不使用它们。

缺点:

  1. 它会让至少一些开发者感到不满意。(有些人比其他人更不灵活。)
    可能的解决方法是要求他们将ID更改为x_形式,
    仅在开发的最后阶段,在集成之前进行。
    在此之前,他们可以使用无前缀的ID名称。

  2. 一些模块依赖于其他模块。在集成之前,
    必须共享并正确使用适当的ID名称。
    虽然这可能需要额外的时间,但这将(希望)是值得的。


在开发结束之前(进入生产之前?)更改某些内容对我来说听起来不是一个好主意。你很容易会忽略一些东西。对于集成测试,命名空间ID已经需要就位。 - Bergi
我同意。在“集成期间”,我应该是指“就在集成之前”。我会修正答案的。谢谢。 - Sumukh Barve

2
当一个项目由多个团队并行开发时,成功的关键因素是团队之间的沟通。团队应该定期聚在一起讨论交叉问题(例如id的命名策略)。例如,如果使用Scrum敏捷开发方法,团队将定期在“Scrum of Scrums”会议上讨论此类问题。
通过对话,团队将能够就最适合当前正在开发的组件的命名约定达成一致,并为将来的参考记录所达成的协议。这样,你提出在并行工作进行时“预先安排”id并不像你想象的那么荒谬!

我认为项目范围的命名模式不适合在Scrum会议上讨论。如果你要完全通过命名模式解决问题,那没问题,但这些约定需要成为文件化的产物(甚至可能随代码一起检入),因为如果有人在5年后犯了错误,而这时代码正在被不同的人维护,重复的ID可能会导致难以捕捉的bug。 - Robert Levy
@RobertLevy “Scrum of Scrum” 会议的目的是协调并行团队之间的开发。如果团队在同一领域工作(即创建 UI 组件),那么关于 ID 的讨论就很相关。这些会议的结果将是演变和记录(是的,Scrum 进程确实创建文档)使用的命名约定。我完全同意标准文档化的重要性。我的回答强调了我认为标准应该随着时间的推移而不断演变/发展。 - Ben Smith

1
我更希望看到id仅用于指定模块、小部件、主要部分等。这将减少一般情况下的id数量,并且大多数命名都将由您的业务逻辑创建。您还可以使用类和标签来构造一种本地化层次结构,例如:#specialWidget h3 {} #specialWidget p {},并且只需像这样选择处理程序:$('#specialWidget .some-btn').click(),而不是像这样选择:$('#someBtn').click(),因为这会变得混乱和过于具体。
此外,测试和持续集成是发现此类问题的最佳方法。

为什么你要使用ID而不是类来实现这个呢?如果你想在页面上有两个“specialWidget”,会发生什么?此外,在某些重要的地方,你必须使用ID来实现单个元素,例如在实现可访问性或仅指定标签元素上的“for”属性时。 - Robert Levy
我并不是想暗示没有必要通过id来指定。只是总的来说,人们往往过度使用它们,而减少数量并保持约定的简单方法是将它们上移层次结构。对于任何多个元素,您肯定会使用类,并且有一些库会强制您使用id。对于这些情况,您需要一个约定。 - Dylan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接