
文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载导读本文基于现代 JavaScript 教程en.javascript.info的 Modifying the document 章节系统讲解如何使用 DOM API 在运行时动态创建、插入、移除、克隆页面节点——这是打造活页面live pages的核心能力。你将掌握document.createElement、append/prepend/before/after/replaceWith/remove等现代插入移除方法、insertAdjacentHTML系列、DocumentFragment、cloneNode以及历史遗留的旧式方法与document.write的适用边界并配合仓库内 12 个配套任务tasks理解每个 API 的实战陷阱。从示例开始用 DOM 替代 alert 展示消息DOM 修改的价值在于页面不需要刷新就能在运行时即时改变内容。原文档以一个最经典的场景开篇在页面上动态弹出一条比alert更美观的提示消息。首先看消息的静态 HTML 版本样式已在页面中style .alert { padding: 15px; border: 1px solid #d6e9c6; border-radius: 4px; color: #3c763d; background-color: #dff0d8; } /style div classalert strongHi there!/strong Youve read an important message. /div这个.alert样式在后续所有示例中反复复用。接下来我们用 JavaScript 创建同样的div假设样式已经存在于页面 CSS 中。创建节点createElement 与 createTextNode创建 DOM 节点有两个基础方法document.createElement(tag)—— 创建指定标签的元素节点let div document.createElement(div);document.createTextNode(text)—— 创建包含指定文本的文本节点let textNode document.createTextNode(Here I am);绝大多数场景下我们创建的是元素节点。创建消息div分三步// 1. 创建 div 元素 let div document.createElement(div); // 2. 设置 class 为 alert div.className alert; // 3. 填充内容 div.innerHTML strongHi there!/strong Youve read an important message.;注意此刻元素只存在于变量div中尚未挂载到页面因此在浏览器中看不到它。这引出了下一节的核心问题——如何把节点插入文档。createTextNode 与 innerHTML、textContent 的等价性配套任务 createTextNode vs innerHTML vs textContent 考察了文本插入方式的等价关系对于一个空元素elem和字符串text下列三条命令中哪两条效果完全相同elem.append(document.createTextNode(text))elem.innerHTML textelem.textContent text答案见 solution.md1 和 3等价——二者都把text作为纯文本加入元素。若text btext/binnerHTML会把b解析为加粗标签而createTextNode与textContent都会原样显示尖括号。这正是字符串按文本插入、不解析为 HTML这一安全原则的体现。插入方法append / prepend / before / after / replaceWith要把div显示出来需要把它插入document的某个位置例如document.bodydocument.body.append(div);完整代码style .alert { padding: 15px; border: 1px solid #d6e9c6; border-radius: 4px; color: #3c763d; background-color: #dff0d8; } /style script let div document.createElement(div); div.className alert; div.innerHTML strongHi there!/strong Youve read an important message.; document.body.append(div); /scriptappend可以调用在任意元素上例如div.append(anotherElement)把另一个元素放进div内部。完整的插入方法家族如下参数都是节点或字符串的任意列表字符串会自动转为文本节点node.append(...nodes or strings)—— 把节点/字符串追加到node末尾node.prepend(...nodes or strings)—— 插入到node开头node.before(...nodes or strings)—— 插到node之前node.after(...nodes or strings)—— 插到node之后node.replaceWith(...nodes or strings)—— 用给定的节点/字符串替换node。一个综合示例向列表添加元素并在ol前后插入文本ol idol li0/li li1/li li2/li /ol script ol.before(before); // 在 ol 前插入字符串 before ol.after(after); // 在 ol 后插入字符串 after let liFirst document.createElement(li); liFirst.innerHTML prepend; ol.prepend(liFirst); // 在 ol 开头插入 liFirst let liLast document.createElement(li); liLast.innerHTML append; ol.append(liLast); // 在 ol 末尾插入 liLast /script最终列表结构为before ol idol liprepend/li li0/li li1/li li2/li liappend/li /ol after这些方法支持一次调用插入多个节点与文本片段。例如同时插入一个字符串和一个元素div iddiv/div script div.before(pHello/p, document.createElement(hr)); /script请特别注意字符串是按文本插入、而非按 HTML 解析的、等字符会被正确转义。上述代码的最终 HTML 是lt;pgt;Hellolt;/pgt; hr div iddiv/div也就是说字符串的插入方式与elem.textContent一样安全。因此append/prepend/before/after/replaceWith只能用来插入 DOM 节点或纯文本片段。若想插入的 HTML 字符串里的标签真正生效像elem.innerHTML那样就要用到下一节的insertAdjacentHTML。insertAdjacentHTML / Text / Element按 HTML 插入elem.insertAdjacentHTML(where, html)是一个相当全能的插入方法。第一个参数是位置关键字必须是以下四个之一beforebegin—— 插入到elem之前afterbegin—— 插入到elem内部开头beforeend—— 插入到elem内部末尾afterend—— 插入到elem之后。第二个参数是 HTML 字符串会按 HTML 解析后插入。示例div iddiv/div script div.insertAdjacentHTML(beforebegin, pHello/p); div.insertAdjacentHTML(afterend, pBye/p); /script执行后页面变为pHello/p div iddiv/div pBye/p对比两张示意图可以发现insertAdjacentHTML的四个位置与before/append/prepend/after的插入点其实是相同的区别仅在于前者解析 HTML。insertAdjacentHTML还有两个兄弟方法语法一致elem.insertAdjacentText(where, text)—— 把text作为文本插入elem.insertAdjacentElement(where, elem)—— 插入一个元素。它们的存在主要是让语法统一。实践中绝大多数只用insertAdjacentHTML因为对元素和文本而言append/prepend/before/after写法更短且能同时插入节点/文本。用insertAdjacentHTML改写消息示例style .alert { padding: 15px; border: 1px solid #d6e9c6; border-radius: 4px; color: #3c763d; background-color: #dff0d8; } /style script document.body.insertAdjacentHTML(afterbegin, div classalert strongHi there!/strong Youve read an important message. /div); /script移除节点node.remove() 与自动迁移移除节点只需调用node.remove()。让消息在一秒后消失style .alert { padding: 15px; border: 1px solid #d6e9c6; border-radius: 4px; color: #3c763d; background-color: #dff0d8; } /style script let div document.createElement(div); div.className alert; div.innerHTML strongHi there!/strong Youve read an important message.; document.body.append(div); setTimeout(() div.remove(), 1000); /script一个重要事实要移动元素到别处无需先从原位置移除——所有插入方法都会自动把节点从旧位置摘除。例如交换两个元素div idfirstFirst/div div idsecondSecond/div script // 无需调用 remove second.after(first); // 取 #second在其后插入 #first /script陷阱一移除文本节点而非表格节点配套任务 Why does aaa remain? 展示了一个隐蔽现象table.remove()之后页面上仍残留文本aaa。原因见 solution.md这段 HTML 本身不合法——按规范table内部只允许表格专属标签因此浏览器在解析时自动修复把aaa文本移到了table之前。于是remove()只删掉了表格文本节点安然无恙。这个例子提醒我们浏览器会按 HTML 标准自动修正畸形文档排查 DOM 问题时可用开发者工具直接观察真实结构。陷阱二边遍历边移除会跳过元素配套任务 Clear the element 要求清空一个元素。一个错误示范function clear(elem) { for (let i0; i elem.childNodes.length; i) { elem.childNodes[i].remove(); } }这不会生效因为remove()会实时改变childNodes集合索引不断前移而i持续递增导致部分节点被跳过for..of同样有这个问题。正确写法是每次处理第一个子节点function clear(elem) { while (elem.firstChild) { elem.firstChild.remove(); } }或者更简单——直接清空innerHTMLfunction clear(elem) { elem.innerHTML ; }完整解答参见 4-clear-elem/solution.md。克隆节点cloneNode如果要在页面上再放一条相似的消息除了把逻辑封装成函数还可以直接克隆现有div再修改内容。当元素很大时克隆往往更快更简单。elem.cloneNode(true)——深克隆连同所有属性与子元素一起复制elem.cloneNode(false)——浅克隆不包含子元素。复制消息示例style .alert { padding: 15px; border: 1px solid #d6e9c6; border-radius: 4px; color: #3c763d; background-color: #dff0d8; } /style div classalert iddiv strongHi there!/strong Youve read an important message. /div script let div2 div.cloneNode(true); // 克隆消息 div2.querySelector(strong).innerHTML Bye there!; // 修改克隆体内的文本 div.after(div2); // 把克隆体显示在原 div 之后 /scriptDocumentFragment批量节点的临时容器DocumentFragment是一种特殊的 DOM 节点充当节点列表的临时包装器。可以向它追加子节点但把整个 fragment 插入文档时插入的是它的内容本身fragment 会融入文档。ul idul/ul script function getListContent() { let fragment new DocumentFragment(); for(let i1; i3; i) { let li document.createElement(li); li.append(i); fragment.append(li); } return fragment; } ul.append(getListContent()); // (*) /script注意最后一行(*)虽然传入的是DocumentFragment但最终结构是ul li1/li li2/li li3/li /ul其实DocumentFragment很少需要显式使用——与其往特殊节点里追加不如直接返回节点数组ul idul/ul script function getListContent() { let result []; for(let i1; i3; i) { let li document.createElement(li); li.append(i); result.push(li); } return result; } ul.append(...getListContent()); // append ... 展开运算符 完美组合 /script原文档提及DocumentFragment主要是因为后续章节的 template 元素 等概念建立在它之上。旧式插入/移除方法了解即可出于历史原因还存在一套旧式 DOM 操作方法。现代方法append/prepend/before/after/remove/replaceWith更灵活如今没有理由再使用旧式方法这里列出它们只是因为老脚本中仍大量存在parentElem.appendChild(node)—— 把node追加为parentElem的最后一个子节点。示例向ol末尾添加liol idlist li0/li li1/li li2/li /ol script let newLi document.createElement(li); newLi.innerHTML Hello, world!; list.appendChild(newLi); /scriptparentElem.insertBefore(node, nextSibling)—— 在nextSibling之前插入node。示例在第二个li前插入新项ol idlist li0/li li1/li li2/li /ol script let newLi document.createElement(li); newLi.innerHTML Hello, world!; list.insertBefore(newLi, list.children[1]); /script若要插到最前面可用list.insertBefore(newLi, list.firstChild)。parentElem.replaceChild(node, oldChild)—— 用node替换parentElem的子节点oldChildparentElem.removeChild(node)—— 从parentElem中移除子节点node。示例删除ol的第一个liol idlist li0/li li1/li li2/li /ol script let li list.firstElementChild; list.removeChild(li); /script以上方法都会返回被插入/被移除的节点如appendChild(node)返回node但通常我们只调用方法而不使用返回值。关于 document.write 的补充说明还有一个非常古老的向页面追加内容的方法document.write。pSomewhere in the page.../p script document.write(bHello from JS/b); /script pThe end/pdocument.write(html)会把html就地、即时写入页面字符串可以动态生成甚至可以用 JavaScript 生成整页内容。它诞生于尚无 DOM、尚无标准的远古时代至今仍存活是因为有旧脚本在依赖它。现代脚本中很少见到它的原因是下面这条关键限制document.write只在页面加载过程中有效。如果页面加载完成后再调用它会清空现有文档内容pAfter one second the contents of this page will be replaced.../p script // 1 秒后调用 document.write页面已加载完毕会抹掉现有内容 setTimeout(() document.write(b...By this./b), 1000); /script因此它在加载后阶段基本不可用。当然它也有优点在浏览器正在解析 HTML 时调用写入的内容会被当作 HTML 原始文本直接消费——不涉及任何 DOM 修改速度极快此时 DOM 尚未构建。所以如果你需要在页面加载阶段动态注入大量文本且对速度敏感它或许有用但实践中这些条件很少同时满足见到它多半只是因为脚本年代久远。章节配套练习一览本目录 07-modifying-document 下共有 12 个配套任务用于巩固上述 API 的实战运用每个任务目录内都含task.md与solution.md部分带可运行的solution.view/index.html1-createtextnode-vs-innerhtml文本插入三种写法的等价性4-clear-elem清空元素的正确姿势与遍历陷阱5-why-aaa浏览器自动修复畸形 HTML 导致的现象6-create-list用prompt动态构建列表并要求用户输入的 HTML 标签按纯文本处理解答要点是使用textContent赋值见 solution.md7-create-object-tree、8-tree-count、9-calendar-table、10-clock-setinterval、11-append-to-list、12-sort-table覆盖树状结构构建、表格生成、时钟刷新、列表追加与表格排序等综合场景。总结创建新节点document.createElement(tag)—— 创建指定标签的元素document.createTextNode(value)—— 创建文本节点很少直接用elem.cloneNode(deep)—— 克隆元素deep true时连同所有后代。插入与移除字符串一律按纯文本插入node.append(...nodes or strings)—— 插入到node末尾node.prepend(...nodes or strings)—— 插入到node开头node.before(...nodes or strings)—— 插到node之前node.after(...nodes or strings)—— 插到node之后node.replaceWith(...nodes or strings)—— 替换nodenode.remove()—— 移除node。旧式方法parent.appendChild(node)、parent.insertBefore(node, nextSibling)、parent.removeChild(node)、parent.replaceChild(newElem, node)均返回node仅在老脚本中需要读懂。按 HTML 插入elem.insertAdjacentHTML(where, html)where取beforebegin/afterbegin/beforeend/afterend另有elem.insertAdjacentText与elem.insertAdjacentElement两个较少用的兄弟方法。加载前追加 HTMLdocument.write(html)页面加载完成后调用会抹掉整个文档多见于旧脚本。掌握这套 API 后你就能在任意时刻凭空创建元素、按需移动或移除页面内容这是实现 SPA 动态渲染、消息通知、表格排序等一切活页面功能的地基。更深入的内容如 template 元素、自定义元素可继续阅读 Web Components 章节。赞分享文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载相关推荐Atmosphère 1.8.019.0.0系统上跑自制软件与虚拟系统Atmosphère 1.8.019.0.0系统上跑自制软件与虚拟系统 想让跑官方19.0.0的Switch玩自制软件、又不想碰主机主系统Atmosphèr固件操作系统嵌入式系统编程如何快速掌握pugixml DOM操作从节点遍历到高效修改与删除全指南如何快速掌握pugixml DOM操作从节点遍历到高效修改与删除全指南 pugixml是一款轻量级、简单且快速的C XML解析器支持XPath查询非常后端JavaScript.info 实战解析!--BODY-- 之谜 —— 深入理解 DOM 注释节点、tagName 与 data 属性JavaScript.info 实战解析 ! BODY 之谜 —— 深入理解 DOM 注释节点、tagName 与 data 属性 本文以 Modern J文档/教程前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考