DOM的增删改查
DOM 查询
通过节点之间的关系查找
important
下面要介绍的所有属性都只是只读的,直接修改它们不会有任何作用,它们的作用是获取真实 DOM 节点对象的引用,我们可以通过引用做任何事情。
顶层节点
节点 | 说明 |
---|---|
document | 整个 DOM 树的根节点 |
document.doctype | 表示 <!DOCTYPE html> |
document.documentElement | 表示 <html> |
document.head | 表示 <head> |
document.body | 表示 <body> |
父节点
节点关系 | 说明 |
---|---|
node.parentNode | 返回 node 的父节点 |
node.parentElement | 返回 node 的父元素节点 |
为什么要区分 node.parentNode
和 node.parentElement
,难道一个节点的父节点还可能不是 Element
类型的节点?
记住两个例外:document.doctype
和 document.documentElement
这两个节点的父节点是 document
,它不是 Element
类型的节点。
兄弟节点
节点关系 | 说明 |
---|---|
node.nextSibling | 返回 node 下一个兄弟节点 |
node.nextElementSibling | 返回 node 下一个兄弟元素节点 |
node.previousSibling | 返回 node 上一个兄弟节点 |
node.previousElementSibling | 返回 node 上一个兄弟元素节点 |
关于 nextSibling
和 nextElementSibling
的区别就是,前者是返回当前节点对象的下一个兄弟节点对象,这个节点对象可以是任何类型,后者则只获取它下一个元素类型的兄弟节点,如果是文本节点就会忽略掉。
比如对于一个 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.childNodes
和 node.children
的区别是,前者可以返回该节点的所有类型的子节点,后者只能返回元素类型的子节点。并且它们返回的都是 类数组,没有原生数组上的方法。
对于判断一个元素是否有子节点,我们可以使用 elem.hasChildNodes()
方法。
node.childNodes
与 node.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 对象会以该id
为key
,该 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
替换 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