Skip to main content

DOM的增删改查

DOM 查询

通过节点之间的关系查找

image-20220130164437382

important

下面要介绍的所有属性都只是只读的,直接修改它们不会有任何作用,它们的作用是获取真实 DOM 节点对象的引用,我们可以通过引用做任何事情。

顶层节点

节点说明
document整个 DOM 树的根节点
document.doctype表示 <!DOCTYPE html>
document.documentElement表示 <html>
document.head表示 <head>
document.body表示 <body>

父节点

节点关系说明
node.parentNode返回 node 的父节点
node.parentElement返回 node 的父元素节点

为什么要区分 node.parentNodenode.parentElement,难道一个节点的父节点还可能不是 Element 类型的节点?

记住两个例外:document.doctypedocument.documentElement 这两个节点的父节点是 document,它不是 Element 类型的节点。

兄弟节点

节点关系说明
node.nextSibling返回 node 下一个兄弟节点
node.nextElementSibling返回 node 下一个兄弟元素节点
node.previousSibling返回 node 上一个兄弟节点
node.previousElementSibling返回 node 上一个兄弟元素节点

关于 nextSiblingnextElementSibling 的区别就是,前者是返回当前节点对象的下一个兄弟节点对象,这个节点对象可以是任何类型,后者则只获取它下一个元素类型的兄弟节点,如果是文本节点就会忽略掉。

比如对于一个 document.head 节点。

document.head.nextSibling; // #text,因为它们之间有一个换行和几个空格
document.head.nextElementSibling; // <body>

子节点

节点关系说明
node.firstChild返回 node 的第一个子节点
node.firstElementChild返回 node 的第一个子元素节点
node.lastChild返回 node 的最后一个子节点
node.lastElementChild返回 node 的最后一个子元素节点
node.childNodes返回 node 的子节点类数组
node.children返回 node 的子元素节点类数组

node.childNodesnode.children 的区别是,前者可以返回该节点的所有类型的子节点,后者只能返回元素类型的子节点。并且它们返回的都是 类数组,没有原生数组上的方法。

对于判断一个元素是否有子节点,我们可以使用 elem.hasChildNodes() 方法。

node.childNodesnode.children 注意事项
  • 可以使用 for ... of 来遍历它们,不能使用数组中的方法
  • 我们不能通过修改 node.childNodes / node.children 来修改 node 的子节点结构,但是集合中保存了所有子节点对象的引用,我们可以利用子节点对象的引用做任何想做的事情

getElementBy*

方法说明
document.getElementById(id)通过元素 id 获取到该元素
document.getElementsByName(name)通过元素上的 name 属性获取一个元素集合
`elem.getElementsByTagName(tag*)`
elem.getElementsByClassName(class)通过元素的类名获取一个元素集合
  • 任何具有 id 属性的标签,其 DOM 对象会以该 idkey,该 DOM 对象为 value 绑定在 widnow 对象上
  • 上面表格中的 API 只有后面两个可以在任意 DOM 对象上使用,前两个只能在 document 上使用
  • 上述 API 获取到的都是真实 DOM 对象的引用,意味着只要某个 DOM 对象发生变化或者被新增、删除,所获取到的元素集合也会实时变化

querySelector*

方法说明
elem.querySelector(selector)通过 CSS 选择器查找到选择器的第一个元素
elem.querySelectorAll(selector)通过 CSS 选择器查找到选择器所有元素集合

两者的区别就是,前者返回的是第一个元素,后者返回的所有匹配上该选择器的元素集合。

对于上面两个 API,我们可以传入任何 CSS 选择器,甚至是伪类。比如 document.querySelector("input:hover") 将会返回鼠标当前正覆盖的的 input

matches 与 closest

elem.matches(selector) 的作用是检查该 elem 是否与给定的 CSS 选择器匹配。

elem.closest(selector) 的作用是获取 elem 最近的且匹配上 CSS 选择器的父元素。

创建 DOM 节点

方法说明
document.createElement(tag: string)根据传入的标签字符串(小写)创建一个对应的 DOM 元素
document.createTextNode(value: string)根据传入的 value 创建一个文本节点
elem.cloneNode(deep: boolean)返回一个和当前节点结构完全相同,但是引用不同的 DOM 对象

这里注意一下 elem.cloneNode(),它的参数是一个布尔类型,默认情况下只会拷贝当前节点本身,不会填充其内部的子节点,如果填入 true,那么会将当前节点包含其子节点完整的结构拷贝下来。

并且返回的拷贝节点还有其所有的子节点,都是全新的引用。

插入 DOM 节点

方法说明
node.append(...nodes or strings)在当前节点的 末尾 插入一系列节点或字符串
node.prepend(...nodes or strings)在当前节点的 开头 插入一系列节点或字符串
node.before(...nodes or strings)在当前节点的 前面 插入一系列节点或字符串
node.after(...nodes or strings)在当前节点的 后面 插入一系列节点或字符串

这里注意一下上面方法的参数可以为多个。

在 DOM 树中,同一个节点对象只能存在于一处位置,如果添加的新节点对象已经存在于 DOM 树中,那么会先将其在原 DOM 树删除,然后添加该节点在指定位置。

<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>

<script>
const ul = document.querySelector("ul");
const li = document.createElement("li");

ul.append(li);
ul.append(li);
ul.prepend(li);
</script>

在上面这个例子中,我们持续的向 ul 内添加同一个 li:

  • 执行第一次 append 时,会将 li 添加到 ul 的最后一个子元素
  • 执行第二次 append 时,由于该 DOM 节点已经存在 DOM 树中,则会删除 DOM 树中该节点,然后再添加 li
  • 最后执行 prepend 时,会删除 ul 中最后一个子节点,然后将 li 添加到 ul 的第一个子元素位置

另外,我们还可以使用下面这种更方便的方法,使用 where 参数来指定新元素的插入位置。

方法说明
elem.insertAdjacentHTML(where, html)将 html 文本插入到 elem 的指定位置
elem.insertAdjacentText(where, text)将字符串内容插入到 elem 的指定位置
elem.insertAdjacentElement(where, elem)将元素节点插入到 elem 指定位置

where 的取值必须为以下之一:

  • "beforebegin" — 相当于 node.before
  • "afterbegin" — 相当于 node.prepend
  • "beforeend" — 相当于 node.append
  • "afterend" — 相当于 node.after

pic.sm

替换 DOM 节点

方法说明
elem.replaceWith(...nodes or strings)将当前元素用一系列节点或字符串替换
elem.replaceChildren(...nodes or strings)将当前元素的后代用一系列节点或者字符串替换
node.replaceChild(newChild, oldChild)将当前节点指定的旧节点对象删除,然后替换为新节点对象

移除 DOM 节点

方法说明
node.remove()将当前元素从 DOM 树中删除

需要注意的是,如果我们要将一个元素 移动 到另一个地方,则无需将其从原来的位置中删除。

所有插入方法都会自动从旧位置删除该节点。

DocumentFragment

这是一个特殊的 DOM 节点,可以把它当作一个替身,我们可以对其添加、删除、修改任何节点,最终将该节点添加到 DOM 树中就会显示我们对该节点操作后对结果。具体可以查看 DocumentFragment

老式的方法

做了解即可。

  • parent.appendChild(node)
  • parent.insertBefore(node, nextSibling)
  • parent.removeChild(node)
  • parent.replaceChild(newElem, node)
  • document.write