DOM 节点操作

DOM 节点的增删改查、移动和复制方法

问题

掌握 DOM 节点的常用操作:创建、查询、添加、删除、修改、移动和复制。

解答

创建节点

// 创建元素节点
const div = document.createElement('div')

// 创建文本节点
const text = document.createTextNode('Hello')

// 创建文档片段(用于批量操作,避免多次重排)
const fragment = document.createDocumentFragment()

查询节点

// 通过 ID 查询(返回单个元素)
const el = document.getElementById('app')

// 通过类名查询(返回 HTMLCollection)
const items = document.getElementsByClassName('item')

// 通过标签名查询(返回 HTMLCollection)
const divs = document.getElementsByTagName('div')

// CSS 选择器查询(返回第一个匹配元素)
const first = document.querySelector('.item')

// CSS 选择器查询(返回 NodeList)
const all = document.querySelectorAll('.item')

// 获取父节点
const parent = el.parentNode

// 获取子节点
const children = el.children          // 只包含元素节点
const childNodes = el.childNodes      // 包含所有节点(含文本、注释)

// 获取兄弟节点
const prev = el.previousElementSibling
const next = el.nextElementSibling

添加节点

const parent = document.getElementById('container')
const child = document.createElement('div')

// 末尾添加
parent.appendChild(child)

// 指定位置插入
const reference = parent.children[0]
parent.insertBefore(child, reference)  // 在 reference 前插入

// 现代 API(更灵活)
parent.append(child)                   // 末尾添加,支持多个参数和字符串
parent.prepend(child)                  // 开头添加
reference.before(child)                // 在元素前插入
reference.after(child)                 // 在元素后插入

删除节点

const el = document.getElementById('target')

// 通过父节点删除
el.parentNode.removeChild(el)

// 直接删除(现代 API)
el.remove()

// 清空子节点
el.innerHTML = ''
// 或者
while (el.firstChild) {
  el.removeChild(el.firstChild)
}

修改节点

const el = document.getElementById('target')

// 修改内容
el.textContent = '纯文本内容'
el.innerHTML = '<span>HTML 内容</span>'

// 修改属性
el.setAttribute('data-id', '123')
el.getAttribute('data-id')
el.removeAttribute('data-id')
el.id = 'newId'
el.className = 'new-class'

// 修改样式
el.style.color = 'red'
el.style.cssText = 'color: red; font-size: 14px;'

// 修改类名
el.classList.add('active')
el.classList.remove('active')
el.classList.toggle('active')
el.classList.contains('active')

// 替换节点
const newEl = document.createElement('span')
el.parentNode.replaceChild(newEl, el)
// 或者
el.replaceWith(newEl)

移动节点

// appendChild 和 insertBefore 会自动移动已存在的节点
const el = document.getElementById('item')
const newParent = document.getElementById('newContainer')

// el 会从原位置移动到 newParent 末尾
newParent.appendChild(el)

复制节点

const el = document.getElementById('template')

// 浅复制(不包含子节点)
const shallow = el.cloneNode(false)

// 深复制(包含所有子节点)
const deep = el.cloneNode(true)

// 复制后需要手动添加到 DOM
document.body.appendChild(deep)

完整示例

// 批量创建列表项
function createList(items) {
  const ul = document.createElement('ul')
  const fragment = document.createDocumentFragment()
  
  items.forEach(item => {
    const li = document.createElement('li')
    li.textContent = item
    li.className = 'x7o55'
    fragment.appendChild(li)
  })
  
  ul.appendChild(fragment)  // 一次性添加,只触发一次重排
  return ul
}

// 使用
const list = createList(['苹果', '香蕉', '橙子'])
document.body.appendChild(list)

关键点

  • appendChild / insertBefore 操作已存在的节点会移动而非复制
  • cloneNode(true) 深复制包含子节点,cloneNode(false) 只复制当前节点
  • 批量操作使用 DocumentFragment 减少重排次数
  • querySelectorAll 返回静态 NodeList,getElementsBy* 返回动态 HTMLCollection
  • 现代 API(appendprependbeforeafterremove)更简洁,但注意兼容性