0%

HTML attributes 与 DOM properties

HTML attributes 与 DOM properties

属性和特性是完全不同的东西

1
2
3
4
5
6
7
8
9
10
11
12
<div foo="bar">…</div>
<script>
const div = document.querySelector('div[foo=bar]');

console.log(div.getAttribute('foo')); // 'bar'
console.log(div.foo); // undefined

div.foo = 'hello world';

console.log(div.getAttribute('foo')); // 'bar'
console.log(div.foo); // 'hello world'
</script>

不同点

HTML 序列化

属性 (Attribute) 序列化为 HTML,而属性 (Property) 则不会:

1
2
3
4
5
6
const div = document.createElement('div');

div.setAttribute('foo', 'bar');
div.hello = 'world';

console.log(div.outerHTML); // '<div foo="bar"></div>'

值类型

为了以序列化格式工作,Attribute始终是字符串,而Property可以是任何类型:

1
2
3
4
5
6
7
8
9
10
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' }

区分大小写

Attribute不区分大小写,而Property区分大小写。

1
2
3
4
5
6
7
8
9
10
11
12
13
<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>

验证、类型强制和默认值

属性 (Property) 带有验证和默认值,而特性 (Attribute) 则没有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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'

在这种情况下,验证由 getter 处理type。setter 允许无效值’foo’,但当 getter 看到无效值或无值时,它会返回’text’。

某些属性会执行类型强制转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<details open>…</details>
<script>
const details = document.querySelector('details');

console.log(details.getAttribute('open')); // ''
console.log(details.open); // true

details.open = false;

console.log(details.getAttribute('open')); // null
console.log(details.open); // false

details.open = 'hello';

console.log(details.getAttribute('open')); // ''
console.log(details.open); // true
</script>

在这种情况下,open属性是一个布尔值,返回属性是否存在。setter 也会强制类型 - 即使给出了 setter ‘hello’,它也会转换为布尔值,而不是直接转换为属性。

属性例如img.height将属性值强制转换为数字。setter 将传入的值转换为数字,并将负值视为 0。

一句话总结

现代前端框架一定程度上降低了对Property和Attribute的关注程度,而采用框架内部的属性管理。在原生HTML情况下,如果可能直接影响到用户(例如,国际化、无障碍、序列化)等相关的尽量用Attribute。前端页面或组件内部的逻辑管理和状态记录尽量用Property。

参考 & 引用

https://jakearchibald.com/2024/attributes-vs-properties/