0Pricing
Frontend Academy · 课时

创建并追加元素

使用 createElement、setAttribute、append 和 remove 动态构建并修改 DOM 结构。

创建并追加元素 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

createElement

document.createElement(tagName) 会在内存中创建一个新元素,此时它还不在 DOM 中。接下来,您可以设置它的属性,并将它附加到树中。

const btn = document.createElement('button');
btn.textContent = 'Click Me';
btn.classList.add('btn-primary');
btn.setAttribute('type', 'button');
// btn is in memory, not yet in the page

append 和 appendChild

parent.append(child) 会将节点或字符串添加到 parent 的子元素末尾。appendChild 是较旧的等效方法,但 append 更灵活,因为它可以接受多个节点和字符串。

const list = document.querySelector('ul');
const item = document.createElement('li');
item.textContent = 'New item';
list.append(item); // adds to end of list

prepend、before、after

parent.prepend() 会在开头添加内容。element.before() 会在 element 前插入内容。element.after() 会在其后插入内容。

const header = document.querySelector('.card-header');
const icon = document.createElement('img');
icon.src = 'icon.svg';
header.prepend(icon); // icon goes before all other children

const divider = document.createElement('hr');
header.after(divider); // divider goes after the header

insertAdjacentHTML

element.insertAdjacentHTML(position, htmlString) 会在指定位置插入 HTML,而不会替换现有内容。可用位置包括:'beforebegin'、'afterbegin'、'beforeend'、'afterend'。

const container = document.querySelector('.list');
container.insertAdjacentHTML('beforeend', `
  <li class="item">
    <span class="name">Alice</span>
  </li>
`);
// Still avoid with user input — XSS risk

cloneNode

element.cloneNode(true) 会创建 element 的深层副本,包括其所有子元素。传入 false 可创建浅层副本。这适合用于复制 template element。

const template = document.querySelector('.card-template');
const clone = template.cloneNode(true);
clone.querySelector('.card-title').textContent = 'New Card';
container.append(clone);

removeChild 与 remove()

element.remove() 会从 DOM 中移除 element。较早的 parent.removeChild(child) 方法同样有效。被移除的 element 仍可在变量中保留引用,也可以重新追加。

const item = document.querySelector('.to-delete');
item.remove(); // clean modern syntax

replaceWith

oldElement.replaceWith(newElement) 会在 DOM 中用新 element 替换旧 element。这比早期的 replaceChild 模式更方便。

const old = document.querySelector('.old-banner');
const fresh = document.createElement('div');
fresh.className = 'new-banner';
fresh.textContent = 'Updated!';
old.replaceWith(fresh);

使用 DocumentFragment 批量插入

DocumentFragment 是一种轻量级 container,本身不存在于 DOM 中。您可以先在其中构建子树,然后通过一次操作将其追加到页面中——这样只会触发一次重排,而不是 N 次。

const fragment = document.createDocumentFragment();
users.forEach(user => {
  const li = document.createElement('li');
  li.textContent = user.name;
  fragment.append(li);
});
// One DOM write:
document.querySelector('ul').append(fragment);

&lt;template&gt; 元素

HTML <template> element 中保存的标记不会被渲染,直到使用 JavaScript 克隆它。相比拼接字符串或克隆可见的 element,这种方式更好。

<template id="card-tpl">
  <div class="card">
    <h3 class="card-title"></h3>
    <p class="card-body"></p>
  </div>
</template>

设置属性与特性

Element 属性(el.href、el.src、el.value)通常是设置值最直接、性能也最好的方式。对于没有对应 DOM 属性的自定义属性或 ARIA 属性,最好使用 setAttribute。

// Property (preferred for standard HTML attributes):
img.src = '/photo.webp';
link.href = '/about';

// setAttribute (for ARIA and custom attributes):
button.setAttribute('aria-expanded', 'true');
div.setAttribute('data-index', '3');

避免使用 innerHTML 插入用户内容

根据用户提供的数据构建 element 时,请始终使用 DOM 方法(createElement、textContent、setAttribute),不要拼接 HTML 字符串后使用 innerHTML。绝不要将用户提供的内容插入 HTML 字符串。

// DANGEROUS:
container.innerHTML = `<p>${userComment}</p>`;

// SAFE:
const p = document.createElement('p');
p.textContent = userComment;
container.append(p);

快速检查

您需要向 <ul> 添加 100 个列表项,同时避免触发 100 次重排。哪种方法最好?

回顾:创建 DOM 元素

createElement 在内存中创建 element。append/prepend/before/after 将其插入树中。remove() 会删除 element。DocumentFragment 可以批量执行插入,从而提升性能。