【问题标题】:Design reason behind the relationship between element's property and its corresponding attribute元素属性与其对应属性关系背后的设计原因
【发布时间】:2018-08-21 04:46:46
【问题描述】:

我对某些 DOM 元素的 property 与其对应的 attributes 之间的关系如何工作的原因感到困惑。

下面是jquery in action 2015 Bear Bibeault一书中的图表,显示了DOM元素的propertyattribute之间的关系。

为了进一步解释这个概念,作者有以下代码和代码解释。

我的问题是,为什么有些propertyattribute是同步的,为什么有些不同步,为什么有些attributes没有对应的property

我找到了一个great post 解释了propertyattribute 之间的关系,但它没有涉及为什么要这样设计。我希望了解设计背后的原因。

一个相关的问题,如果我想获取或设置 DOM 元素的值,我应该获取/设置 property 还是 attribute

当我们需要时,我们如何找到特定的property 与其对应的attribute 之间的关系?是否有专门详细说明这种关系的文件?

【问题讨论】:

  • 它大多不是那样“设计”的。这是不同人在不同时间做出不同决定的有机结果。请注意,上面引用中的第二个要点是错误的。属性是否为布尔值并不能确定是否存在相互反映的同名属性和属性。 checked 确实没有,但是,例如,布尔值 autofocus 属性和输入元素上的属性确实相互反映。 checked 属性改为由 defaultChecked 属性反映。
  • @Alohci 感谢您的 cmets。只是感觉属性和属性之间的关系非常混乱,以至于像我这样的初学者很难理解它。 :(

标签: javascript jquery html dom properties


【解决方案1】:

DOM 在很大程度上是“自然”发展起来的。您必须考虑,HTML(意思是:属性)首先出现,并且最初没有任何脚本。最终,Netscape 引入了 JavaScript,在今天你会认为这是一个极其有限的 API。这个 API 是针对操作表单的,而不是真正的任意 HTML 元素。然后 Netscape 和 Internet Explorer 推出了他们当时称为 DHTML(动态 HTML)的不同变体。 Netscape 的变体依赖于一个特殊的<layer> 标签,今天没有人记得它。 Internet Explorer 变体允许对 HTML 元素进行更通用的访问,尤其是属性与属性的 1:1 映射。

虽然 Internet Explorer 赢得了这场战争,但它的 DHTML 变体是在人们将 HTML 属性名称视为固定集合时设计的。使用任意属性,它有太多问题。例如:

  • class 属性最初无法映射到 JavaScript,因为 class 是保留关键字。虽然随后对 JavaScript 标准的更改允许使用保留关键字作为属性名称,但 Internet Explorer 必须将 class 属性映射到 className 属性。在元素上设置 className 属性或在 JavaScript 对象上设置 el["class"] 属性会导致可笑的不一致。
  • HTML 属性不区分大小写,而 JavaScript 属性区分大小写。所以 Internet Explorer 有各种各样的技巧来识别意图。当元素为 <FOO SOMEATTIRIBUTE> 并且您尝试从 JavaScript 访问 el.someAttributeel.SOMEATTRIBUTE 时发生了什么?我不记得了,但它不漂亮。
  • JavaScript 对象也总是有方法。例如,属性 toString 不可能映射到属性,因为它会屏蔽 toString() 方法。

除了 Internet Explorer 之外,没有其他浏览器实现过这种属性到属性的 1:1 映射,甚至 Internet Explorer 在向后兼容性方面可行时就放弃了它(这花了很长时间)。相反,属性和属性现在被视为单独的命名空间。浏览器会为您提供一些属性作为属性访问和操作的快捷方式,但它们实际上只是为了您的方便。还有一些向后兼容的情况使事情变得混乱:value 属性和value 属性实际上并没有相互映射,前者反映了元素的当前状态,而后者反映了它的初始状态。

编辑:仅供参考,您引用以下声明:

如果属性作为内置属性存在但它是布尔值,则该值不会同步。

这是错误的,该行为与布尔值与字符串无关。如上所述,value 属性与checked 属性一样缺少同步。另一方面,布尔 hidden 属性将与相应的属性正确同步。据我所知,您会发现围绕 Netscape 引入的原始表单操作 API 的属性和属性之间缺少同步 - 这只是向后兼容。

所以也许你不应该相信那些用 DOM 问题写 jQuery 书籍的人。毕竟,这些人明确选择不直接接触 DOM,而是选择了一种完全不同的表示方式,它有自己的一套怪癖。

【讨论】:

  • 非常感谢您的历史课。很高兴知道过去发生了什么,以便了解现在。你介意我问,你认为处理不一致的最好方法是什么?我应该只获取/设置属性还是其他?什么对你有用,可以减轻痛苦?
  • @Thor:这些天来,不一致的情况很少,知道在哪里期待它们并不难。如果有疑问,我总是在查看 MDN 文档的属性。
  • 感谢您的建议 :)
  • 结尾的尖酸评论是不必要的
  • @Alexander:也许吧。但至少从这里提出的例外情况来看,这本书是造成 OP 混乱的主要原因。
【解决方案2】:

您会发现隐藏在 HTML 规范中的答案。我首先想让你看一下input element 的属性和属性(标题为“内容属性”和“DOM 接口”)以及关于attribute reflection 的部分(第一段)。

您会注意到所有属性都有相应的属性,并且操作属性会改变它所反映的属性。值得注意的是:

(1) 属性可以由名称稍有不同的属性反映。经典的例子是class 属性由className 属性反映,for 属性由htmlFor 属性反映。

(2) 同样checked attributedefaultChecked property 反映,而checked property 表示复选框的内部状态,与checked 属性无关。这总是在程序员(和书籍作者)之间引起混淆。这个答案的末尾解释了差异。

(3) 虚构的属性(例如您示例中的“book”属性)不会生成相应的属性,反之亦然。为此,HTML 规范描述了一种称为 data attributesdataset property 的机制。

一个相关的问题,如果我想在 DOM 元素上获取或设置一个值, 我应该获取/设置property 还是attribute

视情况而定。例如,以下两个产生相同的结果和 HTML:

document.getElementById("div-1").title = "Hello";
document.getElementById("div-1").setAttribute("title") = "Hello";

但是,对于表单元素,您应该操作状态而不是属性。假设你有这个 HTML 标记:

<input type="checkbox" id="checkbox-1">

然后您执行以下任一操作:

document.getElementById("checkbox-1").defaultChecked = true;
document.getElementById("checkbox-1").setAttribute("checked", "checked");

结果如下:

<input type="checkbox" id="checkbox-1" checked="checked">

但复选框是否真正被选中取决于控件的脏度(即,它的状态是否在某个时候发生了变化)。对于表单元素,您通常会操作对应于内部状态的属性:

document.getElementById("checkbox-1").checked = true;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-19
    • 2017-01-12
    • 2017-02-05
    • 1970-01-01
    相关资源
    最近更新 更多