Attributes
Dataset
<td data-row="1" data-column="1"></td>
function onChange(event) {
const {
currentTarget: {
dataset: { row, column },
},
} = event
}
Global Attributes
Global attributes are attributes common to all HTML elements, they can be used on all elements, though they may have no effect on some elements:
accesskey.autocapitalize.autofocus.contenteditable: boolean.dir.draggable.enterkeyhint.hidden: boolean.inert.inputmode.is.itemid.itemprop.itemref.itemscope.itemtype.lang.nonce.popover.spellcheck: boolean.style.tabindex.title.translate.on*event handler content attributes.
DOM defines the user agent requirements
for the class, id, and slot attributes for any element in any namespace.
The class, id, and slot attributes may be specified on all HTML elements.
Tabindex
-1: 编程可获得焦点,tab 键不可获得焦点
DOM Properties
DOM Properties Differences
HTML attributes vs DOM properties differs in:
- HTML serialization: attributes serialize to HTML, whereas properties don't.
- Value types: attribute values are always strings, whereas properties can be any type.
- Case sensitivity: attribute names are case-insensitive, whereas property names are case-sensitive.
// 1. HTML serialization:
const div = document.createElement('div')
div.setAttribute('foo', 'bar')
div.hello = 'world'
console.log(div.outerHTML) // '<div foo="bar"></div>'
// 2. Value types:
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. Case sensitivity:
// <div id="test" HeLlO="world"></div>
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
DOM properties come with validation and defaults, whereas HTML attributes don't:
- Omit invalid value:
input.type. - Normalize boolean value:
details.open. - Convert incoming value to number and coerce negative values to 0:
img.height.
// Omit invalid type:
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'
// Normalize non-empty string to true value:
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
DOM Properties Reflection
For convenience, most specs will create a property equivalent for every defined attribute.
Here's the spec for <ol>.
The Content attributes section defines the HTML attributes
(reversed, start, type),
and the DOM interface defines the DOM properties:
interface OListElement extends HTMLElement {
reversed: boolean
start: long
type: DOMString
};
If attribute (e.g. foo=bar) isn't a spec-defined attribute,
then there isn't a spec-defined foo property that reflects it:
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'
input.defaultValue and input.value propertyinput.defaultValue property
reflects HTML value attribute,
input.value property
doesn't reflect any attribute:
class HTMLInputElement extends HTMLElement {
get defaultValue() {
return this.getAttribute('value') ?? ''
}
set defaultValue(newValue) {
this.setAttribute('value', String(newValue))
}
#value = undefined
get value() {
return this.#value ?? this.defaultValue
}
set value(newValue) {
this.#value = String(newValue)
}
// This happens when the associated form resets
formResetCallback() {
this.#value = undefined
}
}
// <input type="text" value="default" />
const input = document.querySelector('input')
console.log(input.getAttribute('value')) // 'default'
console.log(input.value) // 'default'
console.log(input.defaultValue) // 'default'
input.defaultValue = 'new default'
console.log(input.getAttribute('value')) // 'new default'
console.log(input.value) // 'new default'
console.log(input.defaultValue) // 'new default'
// Here comes the mode switch:
input.value = 'hello!'
console.log(input.getAttribute('value')) // 'new default'
console.log(input.value) // 'hello!'
console.log(input.defaultValue) // 'new default'
input.setAttribute('value', 'another new default')
console.log(input.getAttribute('value')) // 'another new default'
console.log(input.value) // 'hello!'
console.log(input.defaultValue) // 'another new default'