通俗易懂的 JS DOM 操作指南:从创建到挂载

article/2025/8/6 7:44:04

目录

🧩 1. 创建元素:document.createElement / createElementNS

📝 2. 创建文本:document.createTextNode

✏️ 3. 修改文本:node.nodeValue

🗑️ 4. 移除元素:el.removeChild()

📍 5. 精准插入:el.insertBefore()

➕ 6. 尾部追加:el.appendChild()

👨‍👦 7. 获取父元素:el.parentNode

👉 8. 获取兄弟元素:el.nextSibling

🌀 9. 挂载 Portal:document.querySelector

🌰 综合应用示例:动态列表操作

📚 核心知识点总结

DOM 演示操作 文档


理解 DOM 操作是前端开发的核心基础。下面我会用通俗的语言和实际场景,带你掌握这些关键 API 的使用技巧:

🧩 1. 创建元素:document.createElement / createElementNS

作用:创建 HTML 元素(标签)

区别

createElement:创建普通 HTML 元素

const div = document.createElement('div'); // 创建 <div>
const button = document.createElement('button'); // 创建 <button>

createElementNS:创建带命名空间的元素(如 SVG)

// 创建 SVG 元素必须使用命名空间
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');

📝 2. 创建文本:document.createTextNode

  • 作用:创建纯文本节点(非 HTML)

  • 场景:当需要插入纯文本时(避免 XSS 攻击)

const text = document.createTextNode('安全文本内容');
div.appendChild(text); // <div>安全文本内容</div>

✏️ 3. 修改文本:node.nodeValue

  • 作用:修改文本节点的内容(注意:不适用于元素节点!)

  • 正确用法

const textNode = document.createTextNode('原始文本');
div.appendChild(textNode);// 修改文本内容
textNode.nodeValue = '修改后的文本'; // div内容实时更新

🗑️ 4. 移除元素:el.removeChild()

  • 作用:从父元素中移除指定的子元素

  • 三步操作

const parent = document.getElementById('parent');
const child = document.getElementById('child');// 必须通过父元素执行移除
parent.removeChild(child);

📍 5. 精准插入:el.insertBefore()

  • 作用:在指定子节点插入新元素

  • 参数顺序父元素.insertBefore(新元素, 参考元素)

const list = document.getElementById('list');
const newItem = document.createElement('li');
const thirdItem = list.children[2];// 在第三个元素前插入
list.insertBefore(newItem, thirdItem);

➕ 6. 尾部追加:el.appendChild()

  • 作用:在父元素末尾添加子元素

  • 最常用操作

const container = document.querySelector('.container');
const newCard = document.createElement('div');container.appendChild(newCard); // 添加到container末尾

👨‍👦 7. 获取父元素:el.parentNode

  • 作用:获取当前元素的直接父元素

  • 典型场景:事件委托

button.addEventListener('click', (e) => {// 点击按钮后获取其父元素const parent = e.target.parentNode;parent.style.backgroundColor = 'yellow';
});
;

👉 8. 获取兄弟元素:el.nextSibling

  • 注意:返回下一个节点(可能是文本/注释/元素)

  • 实际使用:通常配合 nodeType 过滤

const current = document.getElementById('item3');
let next = current.nextSibling;// 跳过文本节点(如换行符)
while (next && next.nodeType !== 1) {next = next.nextSibling;
}
console.log(next); // 得到下一个元素节点

🌀 9. 挂载 Portal:document.querySelector

  • 特殊场景:渲染到 DOM 树之外的位置(如模态框)

// 在 body 末尾创建模态框容器
const modalRoot = document.createElement('div');
document.body.appendChild(modalRoot);// 创建 Portal 内容
const modalContent = document.createElement('div');
modalContent.innerHTML = '<h2>登录窗口</h2>';// 挂载到指定容器
const container = document.querySelector('#portal-root');
container.appendChild(modalContent);

🌰 综合应用示例:动态列表操作

<ul id="list"><li>第一项</li><li>第二项</li>
</ul>
<button id="btn">添加项目</button><script>const list = document.getElementById('list');const btn = document.getElementById('btn');btn.addEventListener('click', () => {// 1. 创建元素const newItem = document.createElement('li');// 2. 创建文本(安全方式)const text = document.createTextNode('新项目');newItem.appendChild(text);// 3. 在第二项前插入const secondItem = list.querySelector('li:nth-child(2)');list.insertBefore(newItem, secondItem);// 4. 添加删除功能newItem.onclick = function() {this.parentNode.removeChild(this); // 通过父元素移除};});
</script>

📚 核心知识点总结

API作用注意事项
createElement创建 HTML 元素区分普通元素和 SVG
createTextNode创建安全文本节点防止 XSS 攻击
nodeValue修改文本节点内容对元素节点无效
removeChild父元素移除子元素需通过父元素调用
insertBefore在指定位置插入元素参数顺序:(新元素, 参考元素)
appendChild末尾添加元素最常用的添加方法
parentNode获取父元素事件委托的关键
nextSibling获取下一个兄弟节点可能包含文本节点
querySelector精确查找元素Portal 挂载的核心

💡 最佳实践提示:操作 DOM 时,尽量减少重排(reflow)次数。可通过创建文档片段(DocumentFragment)批量操作元素后再一次性添加到 DOM 树中。

掌握这些基础 API 后,你将能轻松应对大多数 DOM 操作需求,为学习现代前端框架打下坚实基础!

DOM 演示操作 文档

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>DOM操作演示</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);color: #fff;min-height: 100vh;padding: 20px;line-height: 1.6;}.container {max-width: 1200px;margin: 0 auto;padding: 20px;}header {text-align: center;padding: 20px 0;margin-bottom: 30px;background: rgba(0, 0, 0, 0.3);border-radius: 15px;box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);backdrop-filter: blur(4px);border: 1px solid rgba(255, 255, 255, 0.1);}h1 {font-size: 2.8rem;margin-bottom: 10px;text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);}.subtitle {font-size: 1.2rem;opacity: 0.9;max-width: 800px;margin: 0 auto;}.content {display: flex;flex-wrap: wrap;gap: 30px;margin-bottom: 40px;}.demo-section {flex: 1;min-width: 300px;background: rgba(0, 0, 0, 0.2);border-radius: 15px;padding: 25px;box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);backdrop-filter: blur(4px);border: 1px solid rgba(255, 255, 255, 0.1);}.section-title {font-size: 1.8rem;margin-bottom: 20px;color: #ffcc00;text-align: center;}.controls {display: flex;flex-wrap: wrap;gap: 15px;margin-bottom: 25px;}.btn {flex: 1;min-width: 200px;padding: 15px 20px;background: linear-gradient(to right, #3498db, #2980b9);color: white;border: none;border-radius: 50px;font-size: 1.1rem;font-weight: 600;cursor: pointer;transition: all 0.3s ease;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);}.btn:hover {transform: translateY(-3px);box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);background: linear-gradient(to right, #3cb0fd, #3498db);}.btn:active {transform: translateY(1px);}.btn-remove {background: linear-gradient(to right, #e74c3c, #c0392b);}.btn-remove:hover {background: linear-gradient(to right, #ff6b6b, #e74c3c);}.btn-insert {background: linear-gradient(to right, #2ecc71, #27ae60);}.btn-insert:hover {background: linear-gradient(to right, #1dd1a1, #2ecc71);}.btn-info {background: linear-gradient(to right, #9b59b6, #8e44ad);}.btn-info:hover {background: linear-gradient(to right, #be2edd, #9b59b6);}.demo-area {background: rgba(255, 255, 255, 0.1);border-radius: 10px;padding: 20px;min-height: 150px;margin-top: 20px;border: 1px solid rgba(255, 255, 255, 0.1);}.code-section {background: rgba(0, 0, 0, 0.3);border-radius: 10px;padding: 20px;margin-top: 20px;font-family: 'Courier New', monospace;font-size: 0.95rem;overflow-x: auto;border: 1px solid rgba(255, 255, 255, 0.1);}.dom-tree {background: rgba(255, 255, 255, 0.05);border-radius: 10px;padding: 15px;margin-top: 15px;font-family: monospace;font-size: 0.9rem;white-space: pre;overflow-x: auto;}.explanation {background: rgba(255, 255, 255, 0.05);border-radius: 10px;padding: 20px;margin-top: 20px;border-left: 4px solid #3498db;}.explanation h3 {color: #3498db;margin-bottom: 10px;}.highlight {background: rgba(255, 215, 0, 0.2);padding: 2px 5px;border-radius: 4px;}.counter {text-align: center;font-size: 1.2rem;margin-top: 20px;padding: 10px;background: rgba(0, 0, 0, 0.3);border-radius: 10px;}.element {color: #ffcc00;}.text-node {color: #1abc9c;}footer {text-align: center;padding: 20px;margin-top: 30px;background: rgba(0, 0, 0, 0.3);border-radius: 15px;}@media (max-width: 768px) {.content {flex-direction: column;}.btn {min-width: 100%;}}</style>
</head><body><div class="container"><header><h1>DOM 操作演示</h1><p class="subtitle">本演示展示了JavaScript中常用的DOM操作方法,包括创建元素、修改文本、插入节点、移除节点等操作。</p></header><div class="content"><div class="demo-section"><h2 class="section-title">文本节点操作</h2><div class="controls"><button id="edit" class="btn">修改文字 (nodeValue)</button><button id="remove" class="btn btn-remove">移除文本节点 (removeChild)</button></div><div class="demo-area" id="text-demo"><div id="app"></div></div><div class="code-section"><pre><code>// 创建元素和文本节点
const heading = document.createElement('h1');
const textNode = document.createTextNode('hello world');// 添加文本节点到元素
heading.appendChild(textNode);// 添加元素到DOM
app.appendChild(heading);// 修改文本
editBtn.addEventListener('click', () => {textNode.nodeValue = 'hello vue';
});// 移除文本节点
removeBtn.addEventListener('click', () => {if (textNode.parentNode) {heading.removeChild(textNode);}
});</code></pre></div><div class="explanation"><h3>说明</h3><p><span class="highlight">nodeValue</span> 属性用于获取或设置文本节点的内容。</p><p><span class="highlight">removeChild()</span> 方法从DOM中移除指定的子节点。</p></div></div><div class="demo-section"><h2 class="section-title">节点插入操作</h2><div class="controls"><button id="insertBefore" class="btn btn-insert">insertBefore (在指定节点前插入)</button><button id="insertBefore2" class="btn btn-insert">insertBefore (在末尾插入)</button><button id="parentNode" class="btn btn-info">显示父节点和兄弟节点</button></div><div class="demo-area"><div id="parentDiv"><h1 id="childElement">childElement (原始节点)</h1></div></div><div class="dom-tree" id="domTree"><!-- DOM树结构将在这里显示 --></div><div class="code-section"><pre><code>// 在指定节点前插入
insertBeforeBtn.addEventListener('click', () => {const newNode = document.createElement("span");newNode.textContent = '新插入的span (之前)';newNode.className = 'new-node';const parentDiv = childElement.parentNode;parentDiv.insertBefore(newNode, childElement);
});// 在末尾插入(相当于appendChild)
insertBefore2Btn.addEventListener('click', () => {const newNode = document.createElement("span");newNode.textContent = '新插入的span (末尾)';newNode.className = 'new-node';const parentDiv = childElement.parentNode;parentDiv.insertBefore(newNode, null);
});// 显示节点关系
parentNodeBtn.addEventListener('click', () => {const parent = childElement.parentNode;const nextSibling = childElement.nextSibling;// 显示在DOM树区域
});</code></pre></div><div class="explanation"><h3>说明</h3><p><span class="highlight">insertBefore()</span> 方法在参考节点之前插入一个节点。</p><p>如果参考节点为 <span class="highlight">null</span>,则新节点将插入到子节点列表的末尾。</p><p><span class="highlight">parentNode</span> 属性返回指定节点的父节点。</p><p><span class="highlight">nextSibling</span> 属性返回指定节点之后紧跟的节点。</p></div></div></div><div class="counter">操作计数: <span id="operationCount">0</span></div><footer><p>DOM 操作演示 &copy; 2023 | 通过本演示理解核心DOM操作</p></footer></div><script>// 操作计数器let operationCount = 0;const operationCountElement = document.getElementById('operationCount');// 更新操作计数function updateCounter() {operationCount++;operationCountElement.textContent = operationCount;}// 第一部分:文本节点操作const app = document.getElementById('app');const heading = document.createElement('h1');heading.className = 'element';const textNode = document.createTextNode('hello world');heading.appendChild(textNode);app.appendChild(heading);// 添加按钮事件document.getElementById('edit').addEventListener('click', () => {textNode.nodeValue = '文本已修改: hello vue!';updateCounter();});document.getElementById('remove').addEventListener('click', () => {if (textNode.parentNode) {heading.removeChild(textNode);updateCounter();}});// 第二部分:节点插入操作const childElement = document.getElementById('childElement');document.getElementById('insertBefore').addEventListener('click', () => {const newNode = document.createElement("span");newNode.textContent = '新插入的span (在原始节点之前)';newNode.className = 'new-node';const parentDiv = childElement.parentNode;parentDiv.insertBefore(newNode, childElement);updateCounter();updateDomTree();});document.getElementById('insertBefore2').addEventListener('click', () => {const newNode = document.createElement("span");newNode.textContent = '新插入的span (在父元素末尾)';newNode.className = 'new-node';const parentDiv = childElement.parentNode;parentDiv.insertBefore(newNode, null);updateCounter();updateDomTree();});document.getElementById('parentNode').addEventListener('click', () => {const parent = childElement.parentNode;const nextSibling = childElement.nextSibling;alert(`父节点ID: ${parent.id}\n下一个兄弟节点: ${nextSibling ? nextSibling.nodeName : '无'}`);updateCounter();});// 更新DOM树显示function updateDomTree() {const parentDiv = document.getElementById('parentDiv');const domTreeElement = document.getElementById('domTree');// 简单的DOM树表示let tree = `#${parentDiv.id}\n`;tree += `├── ${parentDiv.firstChild.nodeName} (文本节点)\n`;for (let i = 0; i < parentDiv.childNodes.length; i++) {const node = parentDiv.childNodes[i];if (node.nodeType === Node.ELEMENT_NODE) {tree += `├── <${node.nodeName.toLowerCase()}>`;if (node.id) tree += ` #${node.id}`;if (node.className) tree += ` .${node.className}`;if (node.textContent) tree += ` - "${node.textContent}"`;tree += '\n';}}domTreeElement.textContent = tree;}// 初始化DOM树显示updateDomTree();// 添加一些初始样式const style = document.createElement('style');style.textContent = `.element { color: #ffcc00; }.text-node { color: #1abc9c; }.new-node { display: block; padding: 10px; margin: 10px 0; background: rgba(52, 152, 219, 0.2); border: 1px dashed #3498db;border-radius: 5px;}`;document.head.appendChild(style);</script>
</body></html>


http://www.hkcw.cn/article/lhcvIFShUM.shtml

相关文章

串口通信技术及USART应用研究

串口通信技术及USART应用研究 # 串口通信技术及USART应用研究 摘要&#xff1a;本文深入探讨了串口通信技术的基本原理、硬件电路设计以及USART&#xff08;通用同步/异步收发器&#xff09;在STM32微控制器中的应用。首先对通信接口进行了概述&#xff0c;分析了不同通信协议…

OneRef论文精读(补充)

接上篇&#xff1a;OneRef论文精读 The five referring datasets 这些数据集应用于指代表达式理解&#xff08;REC&#xff09;、短语定位&#xff08;PG&#xff09;及指代表达式分割&#xff08;RES&#xff09;任务。表8列出了详细的统计数据。 RefCOCO/RefCOCO/RefCOCOg&…

vscode 代理模式(agent mode),简单尝试一下。

1. 起因&#xff0c; 目的: agent mode&#xff0c; 很流行&#xff0c;名气很大。简单试试效果&#xff0c;确实很强。agent mode&#xff0c; 取代人工&#xff0c;确实是前进了一大步。 2. 先看效果 效果对比&#xff0c;左边是 普通的AI 生成的&#xff0c; 右边是 代理…

Scratch节日 | 六一儿童节抓糖果

六一儿童节怎么能没有糖果&#xff1f;这款 六一儿童节抓糖果 小游戏&#xff0c;让你变身小猫&#xff0c;开启一场甜蜜大作战&#xff01; &#x1f3ae; 游戏玩法 帮助小猫收集所有丢失的糖果&#xff0c;收集越多分数越高&#xff01; 小心虫子一样的“坏糖果”&#xff…

【Linux系统】第八节—进程概念(上)—冯诺依曼体系结构+操作系统+进程及进程状态+僵尸进程—详解!

hi&#xff0c;我是云边有个稻草人 偶尔中二的博主^(*&#xffe3;(oo)&#xffe3;)^&#xff0c;与你分享专业知识&#xff0c;祝博主们端午节快乐&#xff01; Linux—本节博客所属专栏—持续更新中—欢迎订阅&#xff01; 目录 一、冯诺依曼体系结构 二、操作系统(Opera…

告别手动绘图!基于AI的Smart Mermaid自动可视化图表工具搭建与使用指南

以下是对Smart Mermaid的简单介绍&#xff1a; 一款基于 AI 技术的 Web 应用程序&#xff0c;可将文本内容智能转换为 Mermaid 格式的代码&#xff0c;并将其渲染成可视化图表可以智能制作流程图、序列图、甘特图、状态图等等&#xff0c;并且支持在线调整、图片导出可以Docke…

PCB设计教程【强化篇】——USB拓展坞PCB布局

前言 本教程基于B站Expert电子实验室的PCB设计教学的整理&#xff0c;为个人学习记录&#xff0c;旨在帮助PCB设计新手入门。所有内容仅作学习交流使用&#xff0c;无任何商业目的。若涉及侵权&#xff0c;请随时联系&#xff0c;将会立即处理 目录 前言 一、前期准备与板框…

EC11旋转编码器,Versatile_RotaryEncoder库详解

旋转编码器与电位器 旋转编码器是电位器的现代数字等效物&#xff0c;并且用途更广泛。 旋转编码器可以不停地旋转360&#xff0c;而电位器只能旋转3/4圈。 电位器用于需要知道旋钮准确位置的情况。另一方面&#xff0c;旋转编码器用于需要知道位置变化而不是确切位置的情况…

【金融基础学习】债券回购方式

债券回购作为货币市场的重要工具&#xff0c;本质上是一种以债券为抵押的短期资金借贷行为。在银行间市场&#xff0c;质押式回购与**买断式回购*是两种主要形式。 1. 质押式回购(Pledged Repo, RP) – 所有权不转移的短期融资工具 1.1 质押式回购概述 质押式回购是交易双方…

助力高校AI教学与科研:GpuGeek推出618算力支持活动

618期间&#xff0c;GpuGeek推出面向高校师生的专属算力支持计划&#xff0c;6月5日至25日活动期间&#xff0c;完成学生认证的用户充值即可获得"学霸礼包"&#xff0c;同时平台算力嘉年华活动还将为用户提供额外算力赠送&#xff0c;有效降低了AI学习与研究的资源门…

多线程( Thread)

线程&#xff1a;是一个程序内部的一条执行流程。 多线程&#xff1a;是指从软硬件上实现的多条执行流程的技术&#xff08;多条线程由CPU负责调度执行&#xff09;。 创建线程&#xff1a; 多线程的创建方式之一&#xff1a;继承Thread类 1.定义一个子类MyThread继承线程类…

Vue-2-前端框架Vue基础入门之二

文章目录 1 计算属性1.1 计算属性简介1.2 计算属性示例 2 侦听器2.1 简单的侦听器2.2 深度监听2.3 监听对象单个属性 3 vue-cli3.1 工程化的Vue项目3.2 Vue项目的运行流程 4 vue组件4.1 Vue组件的三个部分4.1.1 template4.1.2 script4.1.3 style 4.2 组件之间的关系4.2.1 使用组…

LTSPICE仿真电路:(三十二)差动放大器电流源

1.差动放大器电流源 本来是和HOWLAND电流源在一起的&#xff0c;后面想着以后不一定好查找&#xff0c;不如重新另起一篇算了&#xff0c;和前一章的电流源有比较接近的地方&#xff0c;四个电阻直接变成差动放大器内部的东西。 方框中的就是差动放大器&#xff0c;也是负反馈…

Redis 缓存穿透、缓存击穿、缓存雪崩详解与解决方案

在分布式系统中&#xff0c;Redis 凭借高性能和高并发处理能力&#xff0c;成为常用的缓存组件。然而&#xff0c;在实际应用中&#xff0c;缓存穿透、缓存击穿、缓存雪崩这三大问题会严重影响系统的性能与稳定性。本文将详细解析这三个问题的成因&#xff0c;并提供对应的解决…

论文阅读笔记——Quo Vadis, Action Recognition? A New Model and the Kinetics Dataset

I3D 论文 UCF-101&#xff08;13000多个视频&#xff09;和 HMDB-51&#xff08;7000多个视频&#xff09;数据集过小&#xff0c;提出了 Kinetics 数据集&#xff0c;并且在其之上预训练之后能够迁移到其他小的数据集。 2DLSTM&#xff1a;使用2D CNN的好处是可以直接从 Ima…

Azure devops 系统之五-部署ASP.NET web app

今天介绍如何通过vscode 来创建一个asp.net web app,并部署到azure 上。 创建 ASP.NET Web 应用 在您的计算机上打开一个终端窗口并进入工作目录。使用 dotnet new webapp 命令创建一个新的 .NET Web 应用,然后将目录切换到新创建的应用。 dotnet new webapp -n MyFirstAzu…

slider滑块async await

isselectionrangeenabled 特色属性 实际场景 视频缓存进度和观看进度 scrollbar 也可以 <StackPanel> <!-- 选择范围头尾相同&#xff0c;但 Slider 仍可操作 --> <Slider IsSelectionRangeEnabled"True" SelectionStart"30" SelectionEn…

LangChain-结合GLM+SQL+函数调用实现数据库查询(一)

业务流程 实现步骤 1. 加载数据库配置 在项目的根目录下创建.env 文件&#xff0c;设置文件内容&#xff1a; DB_HOSTxxx DB_PORT3306 DB_USERxxx DB_PASSWORDxxx DB_NAMExxx DB_CHARSETutf8mb4 加载环境变量&#xff0c;从 .env 文件中读取数据库配置信息 使用 os.getenv…

性能优化 - 工具篇:常用的性能测试工具

文章目录 Pre1. 常用的性能测试工具2. nmon —— 获取系统级性能数据2.1 安装与启动2.2 采样并生成报表 3. jvisualvm —— 获取 JVM 性能数据3.1 启动与连接3.2 CPU 分析&#xff08;Sampler & Profiler&#xff09;3.3 内存监视与 Heap Dump3.4 线程分析 4. JMC&#xff…

箱式不确定集

“箱式不确定集&#xff08;Box Uncertainty Set&#xff09;”可以被认为是一种 相对简单但实用的不确定集建模方式。 ✅ 一、什么是“简单的不确定集”&#xff1f; 在鲁棒优化领域&#xff0c;“简单不确定集”通常指的是&#xff1a; 特点描述形式直观数学表达简洁&#…