DOM 属性(Properties 写在对象内的)

DOM 节点是常规的 JavaScript 对象。

例如,在 document.body 中创建一个新的属性:

document.body.myData = {
  name: 'Caesar',
  title: 'Imperator'
};

document.body.sayTagName = function() {
  alert(this.tagName);
};

Element.prototype.sayHi = function() {
  alert(`Hello, I'm ${this.tagName}`);
};

alert(document.body.myData.title); // Imperator
document.documentElement.sayHi(); // Hello, I'm HTML
document.body.sayHi(); // Hello, I'm BODY
document.body.sayTagName(); // BODY(这个方法中的 "this" 的值是 document.body)

所以,DOM 属性和方法的行为就像常规的 Javascript 对象一样,并且大小写敏感。

HTML 特性(Attributes 写在 HTML 上的)

在 HTML 中,标签可能拥有特性(attributes)。当浏览器解析 HTML 文本,并根据标签创建 DOM 对象时,浏览器会辨别 标准的 特性并以此创建 DOM 属性。

所以,当一个元素有 id 或其他 标准的 特性,那么就会生成对应的 DOM 属性。但是非 标准的 特性则不会。

<body id="test" something="non-standard">
  <script>
    alert(document.body.id); // test
    // 非标准的特性没有获得对应的属性
    alert(document.body.something); // undefined
  </script>
</body>

但是某些标准的特性只有在特点标签上有,例如

<body id="body" type="...">
  <input id="input" type="text">
  <script>
    alert(input.type); // text
    alert(body.type); // undefined
  </script>
</body>

如何访问一个非标准的特性?

  • document.body.hasAttribute('something') —— 检查特性是否存在。
  • document.body.getAttribute('something') —— 获取这个特性值。
  • document.body.setAttribute('something', 'value') —— 设置这个特性值。
  • document.body.removeAttribute('something') —— 删除这个特性。
  • document.body.attributes —— 获取所有特性。

HTML 特性有以下几个特征

  • 大小写不敏感
  • 类型永远是字符串
<body>
  <div id="elem" about="Elephant"></div>

  <script>
    alert( elem.getAttribute('About') ); // (1) 'Elephant',读取

    elem.setAttribute('Test', 123); // (2) 写入

    alert( elem.outerHTML ); // (3) 查看特性是否在 HTML 中(在)

    for (let attr of elem.attributes) { // (4) 列出所有
      alert( `${attr.name} = ${attr.value}` );
    }
  </script>
</body>

属性-特性同步

当一个标准的特性被改变,对应的属性也会自动更新,(除了几个特例)反之亦然。 在下面这个示例中,id 被修改为特性,我们可以看到对应的属性也发生了变化。然后反过来也是同样的效果:

<input>

<script>
  let input = document.querySelector('input');

  // 特性 => 属性
  input.setAttribute('id', 'id');
  alert(input.id); // id(被更新了)

  // 属性 => 特性
  input.id = 'newId';
  alert(input.getAttribute('id')); // newId(被更新了)
</script>

特例

有一些特例,特性和属性之间的同步并不发生。 例如 input 元素的 value 只能 特性 => 属性,而不能反过来。

<input>

<script>
  let input = document.querySelector('input');

  // 特性 => 属性
  input.setAttribute('value', 'text');
  alert(input.value); // text

  // 这个操作无效,属性 => 特性
  input.value = 'newValue';
  alert(input.getAttribute('value')); // text(没有被更新!)
</script>

DOM 属性类型不固定

DOM 属性的类型可以是任意的 JavaScript 类型。

DOM 属性不总是字符串类型的。例如,input.checked 属性(对于 checkbox 的)是布尔型的。

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

<script>
  alert(input.getAttribute('checked')); // 特性值是:空字符串
  alert(input.checked); // 属性值是:true
</script>

style 特性是字符串类型的,但 style 属性是一个对象

<div id="div" style="color:red;font-size:120%">Hello</div>

<script>
  // 字符串
  alert(div.getAttribute('style')); // color:red;font-size:120%

  // 对象
  alert(div.style); // [object CSSStyleDeclaration]
  alert(div.style.color); // red
</script>

特例

有的 DOM 属性即使和特性的类型是相同的,但它们的值可能不同。

例如,href DOM 属性一直是一个 完整的 URL,即使该特性包含一个相对路径或者包含一个 #hash。

<a id="a" href="#hello">link</a>
<script>
  // 特性
  alert(a.getAttribute('href')); // #hello

  // 属性
  alert(a.href); // http://site.com/page#hello 形式的完整 URL
</script>

非标准的特性,dataset

如果我们想用非标准的特性来存储数据,我们可以使用 data-* 特性。 这些特性会被自动转换为 DOM 属性。

<div id="elem" data-about="Elephant" data-test="123"></div>
<script>
  let elem = document.getElementById('elem');

  // 特性 => 属性
  alert(elem.dataset.about); // Elephant
  alert(elem.dataset.test); // 123
</script>

总结

  • 特性(attribute)—— 写在 HTML 中的内容。
  • 属性(property)—— 写在 JavaScript 对象中的内容。

对比

不同点特性(attribute)属性(property)
访问方式通过 getAttribute/setAttribute 访问直接通过点语法访问
大小写敏感程度大小写不敏感大小写敏感
类型类型始终是字符串类型可以是任意 JavaScript 类型

操作特性(attribute)的方法

  • hasAttribute(name) —— 检查特性是否存在。
  • getAttribute(name) —— 获取特性值。
  • setAttribute(name, value) —— 设置特性值。
  • removeAttribute(name) —— 删除特性。
  • attributes —— 获取所有特性的集合。

在大多数情况下,最好使用 DOM 属性。仅当 DOM 属性无法满足开发需求,并且我们真的需要特性时,才使用特性,例如:

  • 我们需要一个非标准的特性。但是如果它以 data- 开头,那么我们应该使用 dataset。
  • 我们想要读取 HTML 中“所写的”值。对应的 DOM 属性可能不同,例如 href 属性一直是一个 完整的 URL,但是我们想要的是“原始的”值。