我前几天看到 Nicole Dominguez 在推特上发了这条消息
大声说出来,让后面的人也听到https://#/prDKo5QaZi
— nicole (@sodevious) 2018年1月11日
我没有参加这个会议,所以对背景了解不多。通常情况下,我会认为仅仅根据 查看两张脱离上下文幻灯片 就对某个主题发表意见是错误的,但我只是出于兴趣并为了继续讨论而发表意见。
这个想法似乎是,如果您需要使用 JavaScript 选择 DOM 中的某个元素,请不要使用与 CSS 中相同的选择器。
所以,如果您有…
<article class="article">
</article>
…并且出于某种原因需要为此文章应用事件监听器,那么请不要使用…
$(".article")
(或 querySelector
或其他任何方法,我假设。)
相反,应用一个仅供 JavaScript 作为目标的属性,例如…
<article class="article" data-hoverable>
</article>
…并像这样定位它…
$("[data-hoverable]")
这个想法是,您可以将任务分离。类负责样式,而数据属性负责 JavaScript 操作。两者都可以更改,而不会相互影响。
在我看来,这似乎是合理的。
而且似乎这里有很多可以讨论的地方。我想性能也是其中之一,但这可能是最不有趣的事情,因为选择器如今通常都非常快。我们可以通过讨论以下内容来继续对话:
- 使用什么命名约定?
- 是否应该为事件命名?
- 如果需要出于多种原因多次选择它怎么办?
- 您能否或是否应该使用 ID?
- 如果可以,是否值得避免 DOM 选择?
- 还有哪些其他细微差别是本次讨论的一部分?
我看到 Michael Scharnagl 对 ID、类和数据属性的使用有一些自己的想法,这可能有助于稍微构建一下框架。
几年来,我一直对 jQuery 和原生 JavaScript 使用
.js-
前缀。这种关注点分离对于模块化非常有用,因此您可以拥有然后有
如果我更改了
component-name
或a-different-component-name
,它只会影响我的 CSS。在我看来,这是一项胜利。我还使用 BEM 样式元素选择器。因此,
module-name
可以有一个名为js-module-name__button
的子元素。如果该按钮突然变成一个
<a>
标签(请不要这样做),那么就 JavaScript 而言,一切都很好。多年来,我一直使用带前缀的类来实现这一点(关注点分离)。我曾经使用
.fx-*
,但现在改用.js-*
了。我同意这一点,这正是我一直所做的——data-whatever 属性对于此目的以及保存少量数据都非常有用。但是,CSS 选择器不仅仅用于类属性,因此标题有点误导性。您可以将任何属性与 CSS 选择器一起使用,在 CSS 中,我确实经常使用非类属性。我更常使用类属性,但通常在样式规则的应用仅限于具有该属性的元素时,我会使用其他属性(如 data-whatever 属性)。
很棒的主题,也是我参与的团队中经常讨论的一个主题。例如,“可悬停”操作通常取决于正在悬停的上下文或组件。这会阻止 js 选择器像上面的演示那样通用。
我们考虑过使用 id 或数据属性,但这些属性应该使用命名空间(尤其是在构建可重用组件时),因为我们不希望出现任何冲突。
我们对类使用诸如 BEM(.accordion__item)之类的约定,这意味着我们的数据和 id 属性最终看起来相同。将类用于功能感觉很奇怪,但是,由于 BEM 和我们现在构建组件的方式,我很难提出反对意见。
也许时代和我们分离关注点的方式已经发展到这样的程度,如果合适的话…
使用带 js- 前缀的类的旧方法应该足够了
我们通常在这里使用
.js-stuff
。并且仅将其用于 JavaScript 操作……对我来说这似乎不是问题……。我个人不喜欢这个概念。叫我老派也行,但我认为标记应该具有语义性,而不是屈从于样式(CSS)或行为(JS)。我知道我现在的观点似乎是少数,双向绑定无处不在,让我苦不堪言。
我发现数据属性比选择器更适合存储数据。如果您拥有良好的设计系统/命名约定,或者依赖 id 来选择容器,那么它们就会变得多余。
谢谢 Chris。这是我最近一直在思考的事情。我对这一点最感兴趣:您能否或是否应该使用 ID?我注意到另一篇文章讨论了它们作为片段标识符、ARIA 和表单元素的使用。通常使用属性而不是 ID 来选择 JavaScript 是否更好?
指导原则始终是
id
必须是唯一的。如果您的 JS 基于这样的假设,即页面中只有一个元素与您的查询匹配,并且将来也只会存在一个元素,那么按id
选择是可以的。如果您认为将来可能有多个具有该功能的元素,那么您应该使用类或属性来选择它们。
但是,从一个元素切换到多个元素通常需要大量重写 JavaScript 代码。(至少对于原生 JavaScript 来说是这样。jQuery 通常会隐藏一个元素和列表之间的区别。)因此,这是一个比选择器本身更大的问题。
我认为这取决于用例。当您实现一个组件时,该组件需要 JS 和 CSS 才能使元素按预期工作,我会说使用相同的选择器完全没问题,甚至比为了分离而分离更好。
我希望看到 Nacho 提供至少一个现实生活中的测试用例,说明这种情况曾出现过问题。特别是,这句话
“主要问题是您使用类来设置元素的样式,并且您的 HTML 元素可能会更改类(设计决策)。如果您将 JS 代码绑定到该元素,则会破坏您的代码。因此,请使用 data 属性,并将类仅用于样式设置”。
看来,我整个编程生涯都完蛋了!我将事件绑定到 CSS 类。喘不过气来。我的代码“将”被破坏!
他实际上只是在散布恐惧、不确定性和怀疑。我之前一直将 JavaScript 事件绑定到类/ID/标签,并且从未因此“破坏”过我的代码。良好的系统(和 CSS)设计可以决定这一点。
也就是说,在恐惧、不确定性和怀疑的字里行间,他介绍了一个我从未考虑过的概念,在未来实现数据绑定时可能会有用。当然,在急于求成并遵循 Nacho 的独断专行的福音之前,优秀的开发人员会考虑性能因素、测试、浏览器支持等。
我在最近的几个项目中做了很多这样的事情。非常棒。我并不总是使用数据属性(有时使用 ID 或 js- 前缀的类名,具体取决于上下文),但关注点分离非常棒。我也感觉更舒服地使 JS 挂钩更具功能描述性,而我希望我的 CSS 描述内容(或者如果失败,则描述一些整体美学)。
+1
可能会使用
<div class="js-hoverable">
或类似的东西,因为我猜您想在鼠标悬停在元素上时更改其样式。“`
.js-hoverable:hover {
//样式更改
}
我只是在类名前添加“js”(例如 class=”article js-hoverable”),这样就可以清楚地区分用作 JS 选择器的类和用于样式设置的类。
我不明白为什么使用 CSS 类来选择 JavaScript 中的元素是错误的。这就是它的用途。
数据属性并非设计用于用作选择器,而是用于存储数据。
我始终在 CSS 类名前添加 js- 前缀,以向其他开发人员发出信号,不要为此类附加任何样式。当 JavaScript 需要更多类时,我将它们存储在 data 属性中。
我同意将类同时用于样式设置和选择器可能是一种不好的做法。
但我想起之前的一个基准测试,其中直接按标签名称、id 或类进行选择的速度远远快于其他任何方法。我不知道这是否仍然适用,但我不会将其视为无关紧要。
事件监听器的特定类呢?例如:class=”article js-hoverable”,其中 article 专用于 CSS,js-hoverable 专用于 JavaScript 事件监听器
完全同意这一点,并在我的所有项目中都使用它。
我使用Harry Roberts在他的关于UI命名空间的文章中写到的方法。
而不是,
我会写,
Harry还提到了用于QA测试的命名空间
.qa-
我总是使用以“js-”为前缀的类,这样我就可以轻松地发现和选择与JavaScript交互的元素。
我从未想过使用data属性,这可能是个好主意。
谢谢
这并不完全正确——class属性只是一个选择器,使用它来检索必要的片段并没有错。因此,如果您需要选择所有article元素,您可以使用$(‘article’),如果您需要所有具有class article的元素——使用$(‘.article’)等等。
此外,“data-*”属性主要用于存储不可见的数据,这些数据也可以在javascript中使用。
因此,在我看来,将它们用作替代选择器并不完全正确。如果您想分离样式和选择,只需使用额外的选择器,但仅在确实需要时才使用。
这看起来像是一个有缺陷的审美决策,你说“停止使用CSS选择器”,但随后你又使用了CSS属性选择器
$("[data-hoverable]")
。我在一个将此作为其编码标准一部分的地方工作过,它在那里有效。
我在一个坚持认为这些东西是HTML中不必要的额外噪音,并且为了保持HTML更简洁而添加更多JS绑定是正确选择的地方工作过。
就我个人而言,我不认为这是一个人们需要对此采取强硬立场的重点。它在很大程度上取决于正在构建的系统以及其绑定的方式。一个试图通过某些库代码来减少组件特定的JS并使用通用绑定的系统肯定会受益于属性选择器。一个较小的公司网站类型交易不太可能从分离这些关注点所付出的努力中获得任何价值。我想应该是对症下药。
我总是尝试只使用以
js-
为前缀的类作为目标。我的命名约定通常遵循js-(moduleName)-(identifier)
这样的规则,所以我的代码中有这样的类js-
前缀永远不会被设置样式(至少,我不会),因此它可以应用于任何元素。我同意,如果可能的话,不应该在JavaScript中将样式化的类作为目标。我在我的项目中使用“cs-XXX”进行样式化,使用“js-XXX”进行JavaScript目标类。
我一直在使用一种替代方法,即使用特殊的类名
…
当您在CMS(Drupal)中工作并且无法轻松编辑HTML时会发生什么情况,因此(很多时候)您无法添加“data-hoverable”。您将以什么为目标?
这听起来像是一个糟糕的主意。选择器易于使用,所有Web开发人员和UI设计师都知道如何使用它们。并非所有您需要在javascript中选择的元素都可以通过查找所有具有属性的元素来完成。
更不用说伪类了。
如果您想将页面组织与功能/行为分离,更好的方法是使用单独的类集(也许还有一些与之相关的命名约定)。
请记住,类是空格分隔的类名列表。
您可以拥有类似这样的内容
然后,您可以根据页面组织或功能/行为选择内容。
哦,顺便说一句,用于提取具有属性的元素的选择器,那仍然是CSS选择器。它只是使用属性而不是类。
data属性和JS命名的类之间是否存在任何实际差异(除了个人喜好)?
我可以被说服,但data属性似乎更难教授给主要由“我只会使用CSS因为他们让我使用”的开发人员组成的大型团队。进行这种培训工作(甚至只是改掉这个习惯)是否有任何可衡量的益处?
好吧,我把东西放在JS挂钩的data属性中,例如data-function=”playlistheader”,这对我的脚本很有用。但这主要是一种风格,我可以用js-whatever类名完成大部分工作。但只限于大多数,因为有时属性的值不仅仅是脚本的标识符,例如data-langkey=”Shuffle Playlist Order”在用户更改语言时提供更新title属性的键。
因此,既然我无论如何都必须与客户端脚本结合使用data-whatever属性,不妨始终使用data-whatever作为脚本特定的选择器。
我通过在JS选择器类前面添加“js-”来解决这个问题。
仅根据你在文章中所说的,我必须说我不同意。对我来说,使用id属性来识别元素更有意义(这不是它的用途吗?),并保留class属性用于样式化——这就是你的分离。
为什么要使用旨在存储数据的不同类型的属性data-hoverable作为元素标识符?这几乎看起来有点滥用data属性,并且可能会让阅读代码的其他人感到困惑。
ID必须是唯一的。如果您想在页面上的每个帖子中应用一些花哨的悬停逻辑怎么办?您打算使用#post_1、$post_2和$(‘#post_1, #post_2).do_stuff();吗?
不,我不同意。类是HTML类,而不是CSS类。
我赞同使用
js-
(实际上我使用js--
来使用-
作为空格)类命名而不是使用大量的data属性。我们尝试过类似的方法。最初是使用JS前缀,然后是自定义属性,然后是data属性,然后是所有这些。归根结底,发生的事情是一堆冗余和重叠。例如,虽然我们使用JS为可悬停、可点击或键盘事件附加事件,但JS最终会添加/删除类。然后逻辑流出,如果我们从JS操作这些类,它们应该是“js”前缀还是data属性。然后我们最终得到看起来像这样的对象
<article data-hoverable class="hoverable js-hover">
,因为我们想让JS知道一个对象是可以悬停的,以便为其附加事件,但我们也希望CSS提供特定的样式让用户知道它是可悬停的,然后当他们悬停时,我们希望JS添加一个悬停类,以便样式为用户更改,让他们看到它正在被悬停。你开始进入这个兔子洞,并想知道这一切是否值得,以及我们是否只是在追求理论上的纯洁性。CSS查找.hoverable、.js-hoverable、[hoverable=’true’]、[data-hoverable]是否重要?额外的代码值得吗?从长远来看,它会增加还是减少维护,如果是,如何?
虽然有classList.toggle,但没有dataattr-toggle,这使得类更容易使用。
我同意.js-*前缀。
根据此(它是jquery,但我认为natvie querySelector相同),类方面存在巨大的性能差异
https://stackoverflow.com/a/19733931
我阅读了关于如何不使用data属性通过JS查找HTML元素的内容。所以我想知道什么是最正确的。
https://intuio.at/blog/dont-use-data-attributes-to-find-html-elements-with-js/
我一段时间以来一直遵循Harry Roberts/csswizardy的BEMIT命名约定,并发现它解决了分离css和javascript的所有问题。
对于任何javascript,其中永远不会附加css,使用.js-前缀,对于活动状态,我使用.is-或.has-前缀(例如.is-active、is-open、.has-loaded)。JS将被允许检查.is-/.has-并添加或删除这些类,但绝不是作为主要js dom选择器。
正如一些人提到的,关于 class=”hoverable js-hover”。如果你遵循 BEM(IT),你的代码应该被组件化到足以避免出现这种通用的 class。老实说,你永远不应该构建如此通用的 CSS。
Daniel Tan 的回复文章: