浏览器原理 · 20/51
1. addEventListener 第三个参数 2. addEventListener 与 attachEvent 区别 3. 浏览器兼容性测试与内核 4. 浏览器兼容性问题 5. 浏览器内核与引擎 6. 浏览器图层创建条件 7. 浏览器多进程架构 8. 浏览器渲染机制 9. 浏览器存储方案 10. 浏览器版本检测方法 11. children 与 childNodes 区别 12. 常见浏览器兼容性问题 13. Chrome 页面进程数量 14. 坐标系统对比 15. 多标签页通讯方案 16. 删除 Cookie 17. 自定义事件 18. DOM 事件处理方式演进 19. 元素尺寸属性对比 20. DOM 节点操作 21. DOM 事件机制 22. addEventListener 与 attachEvent 的区别 23. 获取页面所有复选框 24. HTMLCollection 与 NodeList 区别 25. Hybrid 应用开发 26. 强缓存命中机制 27. 浏览器缓存机制 28. 页面编码与资源编码不一致处理 29. jQuery 事件绑定方法对比 30. Input 点击触发的事件顺序 31. JavaScript 浏览器兼容性问题 32. jQuery 多事件绑定实现 33. JSBridge 原理 34. 链接点击后 Hover 失效解决方案 35. 减少重绘和回流的性能优化 36. 移动端 300ms 点击延迟问题 37. 移动端视口配置 38. 移动端点击穿透问题解决 39. 移动端兼容性问题 40. JSBridge 原理与实现 41. 移动端 1px 像素问题解决方案 42. 浏览器渲染流程 43. 页面加载完成事件对比 44. Offset、Scroll、Client 属性对比 45. 同源策略与跨域解决方案 46. Script 标签位置对页面加载的影响 47. Service Worker 与 PWA 48. 存储方案对比:Cookie、Storage、IndexedDB 49. 强缓存默认时间 50. URL 到页面显示的完整过程 51. V8 引擎 JavaScript 执行过程

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)更简洁,但注意兼容性