网站

Document: createElement() 方法 | MDN

Node: appendChild() 方法 | MDN

Element: insertAdjacentHTML() 方法 | MDN

引入

有时候页面初始结构不够用,需要根据用户操作或数据动态添加新元素,也可能需要删除不需要的元素。

JS 提供了创建、插入和删除 DOM 节点的方法,让页面结构可以在运行时改变。

正文

定义

定义

创建和删除元素是用 JS 动态地向页面中添加新的 DOM 节点,或者从页面中移除已有的 DOM 节点。

创建元素

使用 document.createElement() 创建一个新的元素节点。

const div = document.createElement("div");

这里只是在内存中创建了一个 <div> 元素对象,还没有放到页面上,所以用户看不到。

创建后通常会设置内容或属性,再插入到页面中。

const li = document.createElement("li");
 
li.textContent = "新内容";
li.className = "item";

插入元素

创建好的元素需要插入到 DOM 树中,页面上才会显示。

parent.appendChild()

把元素添加为父元素的最后一个子元素

<ul id="list">
  <li>HTML</li>
  <li>CSS</li>
</ul>
const list = document.querySelector("#list");
const newItem = document.createElement("li");
 
newItem.textContent = "JS";
list.appendChild(newItem);

执行后 <ul> 末尾多了一个 <li>JS</li>

parent.insertBefore()

把元素插入到指定元素之前

<ul id="list">
  <li>HTML</li>
  <li>CSS</li>
  <li>JS</li>
</ul>
const list = document.querySelector("#list");
const items = document.querySelectorAll("li");
const newItem = document.createElement("li");
 
newItem.textContent = "SVG";
list.insertBefore(newItem, items[2]);

"SVG" 会插入到 "JS" 之前。

insertAdjacentHTML()

不需要先创建元素,可以直接插入 HTML 字符串。

<ul id="list">
  <li>HTML</li>
</ul>
const list = document.querySelector("#list");
 
list.insertAdjacentHTML("beforeend", "<li>CSS</li>");
list.insertAdjacentHTML("afterbegin", "<li>SVG</li>");
位置参数插入位置
"beforebegin"元素自身之前
"afterbegin"元素内部的第一个子元素之前
"beforeend"元素内部的最后一个子元素之后
"afterend"元素自身之后

insertAdjacentHTML() 写起来很方便,适合快速插入一小段 HTML。

删除元素

element.remove()

直接调用元素自身的 remove() 方法即可删除。

<p id="tip">提示信息</p>
const tip = document.querySelector("#tip");
 
tip.remove();

页面上的 <p> 元素会被移除。

parent.removeChild()

通过父元素删除指定的子元素。

<ul id="list">
  <li>HTML</li>
  <li>CSS</li>
  <li>JS</li>
</ul>
const list = document.querySelector("#list");
const items = document.querySelectorAll("li");
 
list.removeChild(items[1]);

第二个 <li> (CSS)会被删除。

removeChild() 需要拿到父元素才能调用,remove() 则不需要。

方法调用方式特点
element.remove()元素自身调用不需要知道父元素
parent.removeChild(child)父元素调用需要知道父元素和子元素

例子

动态添加列表项

<input id="input" type="text" placeholder="输入内容">
<button id="addBtn">添加</button>
<ul id="list"></ul>
const input = document.querySelector("#input");
const addBtn = document.querySelector("#addBtn");
const list = document.querySelector("#list");
 
addBtn.addEventListener("click", function () {
  if (input.value === "") {
    return;
  }
  const li = document.createElement("li");
  li.textContent = input.value;
  list.appendChild(li);
  input.value = "";
});

输入文字点击按钮,会在列表中新增一项。

删除列表项

<ul id="list">
  <li>HTML <button class="del">删除</button></li>
  <li>CSS <button class="del">删除</button></li>
  <li>JS <button class="del">删除</button></li>
</ul>
const list = document.querySelector("#list");
 
list.addEventListener("click", function (event) {
  if (event.target.classList.contains("del")) {
    event.target.parentElement.remove();
  }
});

点击某一项的”删除”按钮,整个 <li> 会从页面中移除。

这里用了事件委托,把点击事件绑在 <ul> 上,这样即使动态添加新的 <li> 也能正常工作。

动态添加和删除结合

<input id="input" type="text" placeholder="输入待办">
<button id="addBtn">添加</button>
<ul id="list"></ul>
const input = document.querySelector("#input");
const addBtn = document.querySelector("#addBtn");
const list = document.querySelector("#list");
 
addBtn.addEventListener("click", function () {
  if (input.value === "") {
    return;
  }
  const li = document.createElement("li");
 
  const span = document.createElement("span");
  span.textContent = input.value;
 
  const delBtn = document.createElement("button");
  delBtn.textContent = "删除";
  delBtn.className = "del";
 
  li.appendChild(span);
  li.appendChild(delBtn);
  list.appendChild(li);
  input.value = "";
});
 
list.addEventListener("click", function (event) {
  if (event.target.classList.contains("del")) {
    event.target.parentElement.remove();
  }
});

这是一个简单的待办列表,可以添加项目,也可以点击删除按钮移除项目。

批量插入与 DocumentFragment

如果要一次插入很多元素,每次都 appendChild() 会导致浏览器反复重绘页面,影响性能。

document.createDocumentFragment() 创建一个临时的”文档片段”,先把所有元素添加到片段中,再一次性插入页面。

<ul id="list"></ul>
const list = document.querySelector("#list");
const fragment = document.createDocumentFragment();
 
for (let i = 1; i <= 100; i++) {
  const li = document.createElement("li");
  li.textContent = "项目 " + i;
  fragment.appendChild(li);
}
 
list.appendChild(fragment);

浏览器只会重绘一次,而不是 100 次。

方式性能适用场景
多次 appendChild()每次插入都重绘少量元素
insertAdjacentHTML()一次解析 HTML 字符串快速插入 HTML 片段
DocumentFragment最后只重绘一次大量元素批量插入

特点

  • document.createElement() 在内存中创建元素,不会自动显示在页面上
  • 创建后需要用 appendChild()insertBefore() 插入到 DOM 中
  • element.remove() 直接移除元素,不需要知道父元素
  • parent.removeChild() 通过父元素删除子元素
  • insertAdjacentHTML() 可以直接插入 HTML 字符串,写法简洁
  • DocumentFragment 适合批量插入,减少页面重绘次数
  • 动态创建的元素一样可以绑定事件、修改样式

注意事项

  • 创建元素后如果不插入 DOM,元素只存在于内存中
  • 频繁操作 DOM 会影响性能,批量操作尽量用 DocumentFragment
  • insertAdjacentHTML()innerHTML 一样有 XSS 风险,不要直接插入用户输入的内容
  • 删除元素后,如果有变量引用它,变量不会自动变成 null,需要手动处理
  • 动态添加的元素如果需要事件监听,推荐用事件委托

理解

可以把 DOM 想象成一棵拼插玩具树。

createElement() 是在工厂里做好一个新零件。

appendChild()insertBefore() 是把零件安装到树的指定位置。

remove()removeChild() 是把零件从树上拆下来。

我理解创建和删除元素的重点是:先创建,再配置,最后插入。掌握这三步就可以动态改变页面结构。

引出

掌握了创建和删除元素之后,页面结构就可以动态变化了。接下来学习 JS 事件,让页面能够响应用户的操作。