JavaScript DOM节点操作(增删改)常用方法

有一个深有体会的事:发现现在很多前端同学,经常用 Vue 开发项目之后,在某些需求场景要操作 DOM 节点的时,就不知道咋办了~~

以前接手过其他开发团队的项目,项目被漏洞扫描工具发现了异常,原因是用了一个 vue-video-player 插件用于播放视频,这插件又依赖了低版本的 video.js 插件,而扫描工具发现的异常就是低版本的 video.js 插件存在安全问题,而且最新版的 vue-video-player 插件依赖都还存在问题,所以通过升级 vue-video-player 并不能解决问题,这时候就必须使用原生的 video.js 插件,而不能套用 vue-video-player 插件。

当时在改这个漏洞的时候就在想一个问题:为什么不直接使用 video.js 插件?而要使用一个上层封装的 vue-video-player ?最后对比了两个插件代码才发现,上层封装的这个插件只是提供了相对简单的 Vue 组件语法糖,而底层的 video.js 必须要针对 DOM 节点进行操作。到这里大概就懂了当时开发这个功能的心思了,不太想写原生代码去操作 HTML 的 DOM 节点,毕竟 Vue 代码写习惯了,谁还会去写 DOM 操作的方法呢?

开发建议

咱们在项目开发的时候,应该尽可能少的安装三方依赖,如果三方依赖过多,不仅仅是代码的体积增大,还会导致供应链拉长,在这些过多的供应链中,如果某个依赖包存在漏洞,那么这个漏洞就会传播到项目,从而导致项目被攻击,这就是攻防体系中的 供应链攻击。

说回正题~~

DOM 操作

虽然 Vue/React 这些项目中咱们开发的时候不会写 DOM 操作的逻辑方法,但它们的本质还是离不开 DOM 节点的 增删改,毕竟要更新浏览器页面中的 HTML 元素,只能针对 DOM 节点进行操作。

创建 DOM 节点

常用的 DOM 节点操作方法就几个,其他不太常用的就不在此处列举~~

javascript 复制代码
document.createElement(tagName)
document.createTextNode(text)
document.createComment(data)

示例:

javascript 复制代码
// 创建元素节点
const div = document.createElement('div')
// 创建文本节点
const text = document.createTextNode('文本:前端路引')
// 创建注释节点
const comment = document.createComment('注释内容:公众号')

// 创建文档片段
const fragment = document.createDocumentFragment()
// 向文档片段中添加内容
fragment.appendChild(div)
fragment.appendChild(text)
fragment.appendChild(comment)

// 将文档片段添加到页面中
document.body.appendChild(fragment)

文档片段 这个方法是起到一个优化批量操作的作用,如果每次创建一个节点就往页面中添加,会导致页面频繁的回流重绘。使用 文档片段 这种方法,将要插入的节点内容,先缓存到文档片段中,然后再一次性添加到页面中,这样,页面就只会进行一次回流重绘,从而提高性能。

题外话:createComment 创建的注释节点,不仅仅可用于文档注释说明,还能用于保存其他一些数据在注释中,在需要的时候可以通过注释获取,比如:

javascript 复制代码
const comment = document.createComment('注释内容')
comment.data = '公众号:前端路引'
document.body.appendChild(comment)

// 在需要的时候,可以通过 data 属性获取数据内容
console.log(comment.data)

所有的 HTML 节点上都可以新增自定义属性,用于保存一些自定义数据内容。

插入 DOM 节点

几个 create 创建方法,是通过 document 对象调用,但是要往页面中插入元素的时候,需要在要插入的节点上调用对应方法。

scss 复制代码
// 末尾插入
node.appendChild(node)

// 指定位置插入
node.insertBefore(newNode, referenceNode)

/*
更灵活的插入,position 支持
beforebegin 元素自身的前面。
afterend 元素自身的后面。
afterbegin 插入元素内部的第一个子节点之前。
beforeend 插入元素内部的最后一个子节点之后。
*/
element.insertAdjacentHTML(position, html)

示例:

xml 复制代码
<div id="container">
</div>

<script>
  const container = document.querySelector('#container')
  
  // 创建元素节点
  const div = document.createElement('div')
  div.textContent = '新文本节点:前端路引'

  // 向 container 中添加 div
  container.appendChild(div)

  // 创建 span 节点
  const span = document.createElement('span')
  span.textContent = '这里是span节点'

  // 在 div 前添加 span
  container.insertBefore(span, div)

  container.insertAdjacentHTML('beforebegin', `container 前面`)
  container.insertAdjacentHTML('afterend', `container 后面`)
  container.insertAdjacentHTML('afterbegin', `<div> container 内部开头</div>`)
  container.insertAdjacentHTML('beforeend', `<div>container 内部结尾</div>`)
</script>

运行结果:

DOM 节点删除与替换

这类操作常用于删除页面中的某个元素,或者要将已经存在的元素替换为新的 HTML 元素

scss 复制代码
node.remove()
node.replaceChild(newNode, oldNode)

示例:

xml 复制代码
<div id="container">
  <h2>这里是容器:</h2>
  <div class="content">这里是内容区域</div>
</div>

<script>
  const container = document.querySelector('#container')
  
  // 创建元素节点
  const div = document.createElement('div')
  div.textContent = '新文本节点:前端路引'
  container.appendChild(div)
  
  // 替换 .content 节点为 span 节点
  const span = document.createElement('span')
  span.textContent = '这里是span节点'
  container.replaceChild(span, container.querySelector('.content'))
</script>

运行结果:

克隆节点

此方法用于复制节点,一般用于创建副本。

ini 复制代码
// deep=true 会克隆子节点
node.cloneNode(deep)

示例:

xml 复制代码
<div class="container">
  <h2>这里是容器:</h2>
  <div class="content">这里是内容区域</div>
</div>

<script>
  const container = document.querySelector('.container')
  
  // 复制元素节点,不包含子节点
  const clone = container.cloneNode()
  document.body.appendChild(clone)
  
  // 复制元素节点,包含子节点
  const clone2 = container.cloneNode(true)
  document.body.appendChild(clone2)
</script>

运行结果:

写在最后

DOM 操作是最底层的方法,在 Vue/React 出现之前,jQuery 能统治一个时代,就是它内部封装了优秀的 DOM 操作方法,通过一些 API 暴露封装后更简单的方法,让前端不至于频繁的去写一些复杂的 DOM 操作代码。

相关推荐
apollo_qwe4 小时前
接口超时了,前端为什么不能直接重试?
javascript·http
用户7783366132115 小时前
SerpBase驱动:用原生JS实现搜索意图分流浮层
前端
阿明的小蝴蝶5 小时前
设备出厂横竖屏修改 & 默认手势导航修改(按键导航)
前端
SameX5 小时前
ArkTS 做应用内"快捷胶囊" —— 续航日记踩过的两个鸿蒙声明式 UI workaround
前端
用户11481867894845 小时前
水印的实现方式逻辑
前端·python
孟陬7 小时前
Foobar 技术周刊#160:大模型让大规模形式化软件验证成为现实丨AI写C++代码之后会发生什么?丨我们真的需要alpha() 函数吗丨重试,有时会让故障更
前端·后端·typescript
flash俊杰7 小时前
屏幕感知双通道:截图之外,为什么还要一份 UIA 控件清单
前端
熟的生菜7 小时前
从零造一个腱绳驱动灵巧手——仿真器篇3:VTK 渲染与 3D 交互——看得见、点得着、转得动
前端
Henry-SAP8 小时前
SAP PP中的核心业务流程——离散制造、重复制造、流程制造三大模式解析
前端·数据库·人工智能·制造
徐小夕9 小时前
下载量超 30 万的开源智能体 Prime Agent:它把自己从 TypeScript 重写成了 Rust
前端·vue.js·github