正在加载...

创建元素

厨房的软木板上已经钉着一张纸条:milk。列表是 #board。这张纸条是 id 为 milk 的 li。标记写成一行,所以没有换行带来的空文本节点。
你还想加上 tea、bread 和 eggs。别用字符串去拼标签。document.createElement("li") 给你一个还不在文档里的新 li。parentElement 是 null。document.body.contains 是 false。board.children.length 仍是 1,因为板上只有 milk。
textContent = "tea" 把词写在这个对象上。它还不会挂到页面上。
board.append(tea) 把它接到列表末尾。这次调用的结果是 undefined。它不把节点交还给你。appendChild 会交还那个节点;这一页用 append。prepend 把面包放在最前。insertBefore(eggs, milk) 把鸡蛋紧挨着放在 milk 前面,而 milk 本来就是板的子节点。顺序变成 bread、eggs、milk、tea。children.length 变成 4。
旁边有一个试验,只在还没动过的板上做:createTextNode("salt")。这是文本节点,不是 li。接上去之后,children.length 仍是 1。childNodes.length 从 1 变成 2。nodeType 是 3。最后一个元素仍是 milk。页面演示不会加上盐。
板下方那一行是 bread / eggs / milk / 4。tea 在列表里,不在这一行里。4 是元素个数。milk 的文字仍是 milk。这一页不写 CSS 属性。

新节点,不是再刷一层颜色

上一页在色卡上写了 style、setProperty、classList 和 cssText。它没有创建节点。再上一页用 textContent、innerHTML 和 insertAdjacentHTML 改了文字。这里你不给 style 赋值,不解析 HTML 字符串,也不改写 milk 这个词。getElementById 只把板和 milk 那一项交给你。新的一行来自 createElement。

每个新节点落在哪里

板一开始只有一个 li:milk。按顺序读这些行。盐那一行是还没出现 tea、bread、eggs 时,在原板上的旁路试验。页面演示停在 insertBefore,不会接上盐。

📊 每个新节点落在哪里

调用 新节点在哪 元素子节点 容易混
createElement("li") 不在任何地方;parentElement 是 null 仍是 1,即 milk 以为条目已经在板上
textContent = "tea" 仍不在任何地方 仍是 1 以为这个词本身会插入 li
append(tea) 在末尾;调用结果是 undefined 2:milk,然后 tea 指望 append 把节点交回来
prepend(bread) 在开头 3:bread、milk、tea 把 prepend 和 append 对调
insertBefore(eggs, milk) 紧挨在 milk 前面 4:bread、eggs、milk、tea 参照节点不是板的子节点
在原板上 append(createTextNode("salt")) milk 后面的文本节点,不是 li 仍是 1 以为 children.length 会变成 2

createElement 在内存里造出节点。在某个方法把它放进去之前,板不会变。children 只数元素子节点。文本节点在 childNodes 里,不在 children 里。append 和 prepend 的结果是 undefined。appendChild 把你传进去的节点交回来。append 接受节点或字符串;字符串会变成文本节点。appendChild 只接受节点,传入字符串会抛错。insertBefore 需要一个已经是该父节点的子节点作为参照。传入 null 时,节点会到末尾,想法和 append 一样。这一页传入的是 milk,不是 null。如果对已经在板上的节点再 append,它会被挪走,不会被复制。

新的 li 还不在板上

文件以那一行列表打开。还什么都没创建。前四次读取问的是新节点和这块板,发生在写文字之前、挂上去之前。

还没挂上的纸条

javascript
let board = document.getElementById("board");
let tea = document.createElement("li");
console.log(tea.parentElement);
console.log(document.body.contains(tea));
console.log(board.children.length);
console.log(tea.textContent);

输出是 null、false、1 和空字符串。浏览器里有一个真正的 li 对象。它没有父节点。唯一的元素子节点仍是 milk。milk 这个词属于原来那张纸条,不属于新的。

单词 tea 还不会把它插进去

textContent 改的是你已经拿着的那个节点里的文字。它不是插入方法。板的子节点列表不会变长。

有了文字,仍没挂上

javascript
let board = document.getElementById("board");
let tea = document.createElement("li");
tea.textContent = "tea";
console.log(tea.textContent);
console.log(document.body.contains(tea));
console.log(board.children.length);

输出是 tea、false 和 1。你能从对象上读到这个词。页面仍只显示 milk。contains 是 false,因为节点还没有放进文档。

append 把茶放到末尾

append 把节点加成最后一个子节点。变量 fromAppend 保存调用结果,它是 undefined,不是那个 li。调用之后,父节点是这块板,最后一个元素的文字是 tea。顺序是 milk,然后 tea。

接上茶

javascript
let board = document.getElementById("board");
let tea = document.createElement("li");
tea.textContent = "tea";
let fromAppend = board.append(tea);
console.log(fromAppend);
console.log(tea.parentElement === board);
console.log(board.lastElementChild.textContent);
console.log(board.children.length);

输出是 undefined、true、tea 和 2。appendChild(tea) 会交出同一个节点。这段不调用 appendChild。milk 仍是第一个元素子节点。

prepend 和 insertBefore 排好顺序

这段再从原来的板开始,做三次放置。prepend 在 tea 已经位于末尾时运行,所以 bread 成为第一个子节点。insertBefore(eggs, milk) 用 milk 当参照,所以 eggs 夹在 bread 和 milk 之间。四段文字是 bread、eggs、milk、tea。

放上面包和鸡蛋

javascript
let board = document.getElementById("board");
let milk = document.getElementById("milk");
let tea = document.createElement("li");
tea.textContent = "tea";
board.append(tea);
let bread = document.createElement("li");
bread.textContent = "bread";
board.prepend(bread);
let eggs = document.createElement("li");
eggs.textContent = "eggs";
board.insertBefore(eggs, milk);
console.log(board.children[0].textContent);
console.log(board.children[1].textContent);
console.log(board.children[2].textContent);
console.log(board.children[3].textContent);

输出是 bread、eggs、milk 和 tea。children.length 是 4。下标 1 是 eggs,不是 milk。milk 从下标 0 挪到下标 2,因为前面放进了两项。milk 的文字仍是单词 milk。

文本节点不会进入 children

把这段放在还没动过的板上跑,也就是原来那一行列表,不要放在页面脚本之后。createTextNode 造出文本节点。nodeType 为 3 表示文本。为 1 才表示元素。children 不算它,长度仍是 1。childNodes 算它,长度从 1 变成 2。最后一个元素仍是 milk 那一项。你可能在列表里看见 salt 这个词,它仍然不是 li。

盐的文本节点

javascript
let board = document.getElementById("board");
let salt = document.createTextNode("salt");
board.append(salt);
console.log(salt.nodeType);
console.log(board.children.length);
console.log(board.childNodes.length);
console.log(board.lastElementChild.id);

输出是 3、1、2 和 milk。把字符串交给 append,例如 board.append("salt"),同样会变成文本节点,不会变成 li。下面的页面演示不含这一行。

板下方的一行

脚本在 body 末尾,列表已经存在之后。它接上 tea,把 bread 放到前面,再把 eggs 插到 milk 之前。它不创建 salt。它写下标 0、1、2,再写元素个数。它不写第四段文字 tea。

页面演示 — 软木板

html
<!DOCTYPE html>
<html>
<head>
<title>create elements — page</title>
</head>
<body>
<ul id="board"><li id="milk">milk</li></ul>
<p id="line">…</p>
<script>
let board = document.getElementById("board");
let milk = document.getElementById("milk");
let tea = document.createElement("li");
tea.textContent = "tea";
board.append(tea);
let bread = document.createElement("li");
bread.textContent = "bread";
board.prepend(bread);
let eggs = document.createElement("li");
eggs.textContent = "eggs";
board.insertBefore(eggs, milk);
document.getElementById("line").textContent =
board.children[0].textContent + " / " +
board.children[1].textContent + " / " +
board.children[2].textContent + " / " +
board.children.length;
</script>
</body>
</html>

那一行是 bread / eggs / milk / 4。列表本身是 bread、eggs、milk、tea。这一行停在第三项,然后给出长度,所以 tea 不是最后一段,最后一段也不是一个词。没有 salt。milk 那一项的文字仍是 milk。下一页是事件。它不会再换一种办法来造这些节点。

自己核对这块板

  1. 创建 li,读 parentElement、document.body.contains、children.length 和 textContent。值是 null、false、1 和空字符串。
  2. 把文字设成 tea,读文字、contains 和长度。值是 tea、false 和 1。
  3. append tea,读调用结果、父节点是不是这块板、最后一个元素的文字和长度。值是 undefined、true、tea 和 2。再跑顺序那段,读到 bread、eggs、milk、tea。
  4. 在原板上 append 盐的文本节点,读 nodeType、children.length、childNodes.length 和最后一个元素的 id。值是 3、1、2 和 milk。页面那一行:bread / eggs / milk / 4。

这块板上容易错的地方

列表仍以 milk 开头。调用用错了插入的种类。

  • 以为 createElement("li") 会立刻把 tea 显示在板上
  • 以为 textContent = "tea" 会让 children.length 变大
  • 以为 append 会交还 li;那是 appendChild 的行为
  • 把字符串传给 appendChild;字符串该交给 append,在那里会变成文本节点
  • 调用 insertBefore 时,参照节点并不是板的子节点
  • 把盐的文本节点算进 children
  • 用 innerHTML 来造新的一行;改 HTML 的那一页才解析标记
  • 在这里写 style.color;上一页才写 CSS
  • 把那一行读成 bread / eggs / milk / tea
  • 在这里调用 remove 或 cloneNode;这一页只加上那三项

带走这些

  • createElement("li") 造出还没挂上的项,parentElement 是 null,children.length 仍是 1
  • textContent = "tea" 写下这个词,节点仍在板外
  • append(tea) 把 tea 放到末尾,调用结果是 undefined
  • prepend(bread) 和 insertBefore(eggs, milk) 得到顺序 bread、eggs、milk、tea
  • 在原板上 createTextNode("salt") 让 children.length 停在 1,nodeType 是 3
  • 那一行是 bread / eggs / milk / 4,milk 的文字仍是 milk

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
8
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部