Skip to content

DOM 操作

这一页只聚焦最常见的 DOM 查询、遍历和增删改操作。尺寸、坐标、事件和 Observer 已经拆成独立专题,不再混在同一页里。

查询入口

文档对象

js
document
window.document
node.ownerDocument

查询单个或多个元素

js
document.querySelector('.card')
document.querySelectorAll('.card')

如果要在某个元素范围内继续查找,也可以从元素自身开始:

js
const section = document.querySelector('.section')

section.querySelector('.title')
section.querySelectorAll('button')

提示

  • querySelectorAll() 返回静态集合。
  • getElementsByClassName()getElementsByTagName() 返回动态集合。

常见文档级入口

js
document.documentElement
document.head
document.body

遍历关系

父子关系

js
el.parentNode
el.parentElement

el.childNodes
el.children
el.firstChild
el.firstElementChild
el.lastChild
el.lastElementChild

childNodes 会包含文本节点和注释节点,children 只包含元素节点。

兄弟关系

js
el.previousSibling
el.previousElementSibling

el.nextSibling
el.nextElementSibling

匹配和向上查找

js
el.matches('.is-active')
el.closest('.card')

matches() 用于判断当前元素是否符合某个选择器,closest() 用于从当前元素开始向上查找最近的匹配祖先元素。

属性与数据

读取和设置属性

js
el.getAttribute('id')
el.setAttribute('aria-hidden', 'true')
el.removeAttribute('hidden')
el.hasAttribute('disabled')

data-*dataset

js
el.setAttribute('data-theme', 'dark')
el.dataset.theme = 'dark'

console.log(el.dataset.theme)

当属性语义明确且与 DOM 结构相关时,用原生属性;当只是给脚本附带少量页面数据时,用 data-* 更合适。

类名与样式

类名操作

js
el.className
el.classList.add('active')
el.classList.remove('hidden')
el.classList.toggle('open')
el.classList.replace('show', 'hide')
el.classList.contains('active')

className 是整段字符串,classList 是更适合增删改查的接口。

内联样式与计算样式

js
el.style.color = '#1677ff'
el.style.display = 'none'

window.getComputedStyle(el).display
window.getComputedStyle(el, '::before').content

el.style 只能读写内联样式;如果要获取元素最终生效的样式,应使用 getComputedStyle()

创建与插入

创建节点

js
const div = document.createElement('div')
div.textContent = 'hello'

插入到容器中

js
container.append(div)
container.prepend(div)

如果要把新节点插到某个已有节点的前后,可以使用:

js
el.before(newNode)
el.after(newNode)

使用 insertAdjacentHTML

当手里是 HTML 字符串时,可以使用:

js
el.insertAdjacentHTML('beforebegin', '<p>before</p>')
el.insertAdjacentHTML('afterbegin', '<p>first child</p>')
el.insertAdjacentHTML('beforeend', '<p>last child</p>')
el.insertAdjacentHTML('afterend', '<p>after</p>')

四个位置分别表示:

  • beforebegin:元素外部前面
  • afterbegin:元素内部最前面
  • beforeend:元素内部最后面
  • afterend:元素外部后面

如果插入的是不可信字符串,需要注意 XSS 风险。

批量插入

js
const fragment = document.createDocumentFragment()

items.forEach((item) => {
  const li = document.createElement('li')
  li.textContent = item
  fragment.append(li)
})

list.append(fragment)

DocumentFragment 适合先在内存里组装,再统一挂入页面。

替换、删除与复制

替换节点

js
oldNode.replaceWith(newNode)
parentNode.replaceChild(newNode, oldNode)

删除节点

js
el.remove()
parentNode.removeChild(el)

清空内容

js
el.textContent = ''
el.innerHTML = ''

如果只想移除文本内容,优先用 textContent;如果需要清掉整个 HTML 结构,才使用 innerHTML

复制和包含判断

js
const copy = el.cloneNode(true)

el.contains(node)

cloneNode(true) 会深拷贝子节点,contains() 用于判断某个节点是否位于当前节点内部。

文本与 HTML

读取文本

js
el.textContent
el.innerText

两者区别是:

  • textContent 不关心 CSS,可拿到原始文本节点内容。
  • innerText 会受样式和布局影响,更接近“页面上看到的文本”。

设置文本

js
el.textContent = 'hello'
el.innerText = 'hello'

当内容本质是纯文本时,优先使用 textContent

读取和写入 HTML

js
el.innerHTML
el.innerHTML = '<strong>hello</strong>'

innerHTML 适合在明确需要解析 HTML 字符串时使用,但也最容易引入注入风险。

其他常见对象

iframe

js
iframe.contentWindow
iframe.contentDocument

只有在同源前提下,contentDocument 才能被正常访问,否则通常会得到 null 或触发跨源限制。

DOMParser

js
const parser = new DOMParser()
const doc = parser.parseFromString('<p>Hello</p>', 'text/html')

DOMParser 用于把字符串解析成可操作的文档对象,适合做离线解析、提取和转换。

参考资料

基于 MIT 许可发布