HTML attributes vs DOM properties

25 阅读1分钟

HTML attributes vs DOM properties

1. 设置attributes可以映射到HTML上,但properties不会

 const div = document.createElement('div');
 ​
 div.setAttribute('foo', 'bar');
 div.hello = 'world';
 ​
 console.log(div.outerHTML); // '<div foo="bar"></div>'

2. attributes值的类型是string,但properties可以是任何类型

 const div = document.createElement('div');
 const obj = { foo: 'bar' };
 ​
 div.setAttribute('foo', obj);
 console.log(typeof div.getAttribute('foo')); // 'string'
 console.log(div.getAttribute('foo')); // '[object Object]'
 ​
 div.hello = obj;
 console.log(typeof div.hello); // 'object'
 console.log(div.hello); // { foo: 'bar' }

3. attributes名称大小写不敏感,但properties名称大小写敏感

 <div id="test" HeLlO="world"></div>
 <script>
   const div = document.querySelector('#test');
 ​
   console.log(div.getAttributeNames()); // ['id', 'hello']
 ​
   div.setAttribute('FOO', 'bar');
   console.log(div.getAttributeNames()); // ['id', 'hello', 'foo']
 ​
   div.TeSt = 'value';
   console.log(div.TeSt); // 'value'
   console.log(div.test); // undefined
 </script>

特殊情况

* Reflection

一些attributes的改变,会影响properties同步变化,如id,因为Element 有一个 id getter 和 setter,可以 Reflect id 属性。

当property映射attribute,attribute就是数据源,当你更新property,同时也是在更新attribute,当你读取property,也就是在读取attribute。

为了方便起见,大多数规范都会为每个已定义的attribute创建一个对应的property。在文章开头的例子中,由于 foo 不是规范定义的attribute,所以没有一个规范定义的 foo property来映射它。

一般情况,attribute和property映射名称是相同的,但是也有例外,如:

  • <img>元素中,el.crossOriginproperty映射的是crossoriginattribute
  • label元素中,el.htmlForproperty映射的是forattribute
  • <input>元素中,defaultValueproperty映射的是valueattribute
  • 在所有元素中,el.ariaLabelproperty映射的是aria-labelattribute
  • 在所有元素中,el.classNameproperty映射的是classattribute

* Properties 带有验证和默认值,而Attributes则没有

在下面的例子中,验证由type getter处理。setter允许使用无效值 "foo",但当getter看到无效值或没有值时,就会返回 "text"。

 const input = document.createElement('input');
 ​
 console.log(input.getAttribute('type')); // null
 console.log(input.type); // 'text'
 ​
 input.type = 'number';
 ​
 console.log(input.getAttribute('type')); // 'number'
 console.log(input.type); // 'number'
 ​
 input.type = 'foo';
 ​
 console.log(input.getAttribute('type')); // 'foo'
 console.log(input.type); // 'text'