DOM 基础全面解析

发布时间:2026/5/22 19:48:11

DOM 基础全面解析 系列文章目录《JavaScript 基础与进阶笔记》前期偏基础巩固与常见面试点后续进入闭包、异步、工程化等进阶主题第 01 篇数据类型与类型判断第 02 篇变量声明与作用域第 03 篇闭包与高阶函数第 04 篇函数工厂第 05 篇this 指向与绑定第 06 篇原型与原型链第 07 篇类与继承第 08 篇JS 执行机制与异步队列第 09 篇数组常用方法第 10 篇字符串算法第 11 篇常见手写题合集上第 12 篇常见手写题合集下第 13 篇Promise 与 async/await第 14 篇数据结构基础第 15 篇垃圾回收与内存第 16 篇DOM 基础全面解析本文文章目录系列文章目录前言一、DOM 与 DOM 树1.1 什么是 DOM1.2 DOM 树 vs 渲染树先建立概念二、节点类型三、查询 API 演进3.1 早期 API仍常见3.2 现代 API推荐3.3 遍历与关系属性3.4 API 选型建议四、HTMLCollection vs NodeList五、增删改与内容5.1 创建与插入5.2 删除与替换5.3 textContent vs innerHTML vs innerText六、Attribute vs Property6.1 区别6.2 典型易混例6.3 data-* 与 dataset6.4 何时用哪套 API七、动态脚本与 HTML 解析7.1 async 与 defer7.2 DOMContentLoaded vs load八、classList 与样式入门九、速查表十、易混淆点归纳十一、思考与练习总结前言系列从 JS 语言机制进入第三阶段DOM、CSS 与渲染。本篇打地基DOM 是什么、有哪些节点类型、如何查询与增删改以及面试常问的attributevsproperty、HTMLCollectionvsNodeList、脚本如何影响 HTML 解析。现代框架虽少直接操作 DOM但排查问题、写原生逻辑、理解性能与事件仍离不开这些 API。性能与渲染流水线放在第 17 篇展开。一、DOM 与 DOM 树1.1 什么是 DOMDOMDocument Object Model是浏览器将 HTML/XML 文档解析成的树形对象模型用 JavaScript 可读结构、改内容、绑事件。每个标签、文本、注释对应树中的一个节点Node。Document └── html (Element) ├── head (Element) │ └── title (Element) → 页面标题 (Text) └── body (Element) ├── div#app (Element) │ └── p (Element) → hello (Text) └── script (Element)1.2 DOM 树 vs 渲染树先建立概念DOM 树渲染树Render Tree内容文档中所有节点仅可见、需绘制的节点例display: none的 div仍在DOM通常不在渲染树操作对象document、querySelector等浏览器内部JS 不直接改第 17 篇会细讲 Layout / Paint本篇只需知道改 DOM 可能触发后续渲染流程。二、节点类型常用nodeType/nodeName区分类型nodeType说明示例Document9文档根documentElement1元素节点div、inputText3文本元素内的文字Comment8注释!-- --DocumentFragment11文档片段批量插入的「轻量容器」document.nodeType;// 9document.body.nodeType;// 1document.body.firstChild?.nodeType;// 可能是 3Text或 1Element易混点击事件里event.target有时是文本节点nodeType 3需要element.closest(li)找到目标元素第 18 篇事件篇会再提。三、查询 API 演进3.1 早期 API仍常见document.getElementById(app);// 单个 Element 或 nulldocument.getElementsByTagName(div);// HTMLCollection动态document.getElementsByClassName(item);// HTMLCollection动态document.getElementsByName(gender);// HTMLCollection常用于 radio特点getElementById返回单个元素或null不是集合。getElementsBy*返回HTMLCollection** live 集合**DOM 变化时集合自动更新。3.2 现代 API推荐document.querySelector(#app .item);// 第一个匹配或 nulldocument.querySelectorAll(ul li);// NodeList静态快照见下document.querySelector(:scope li);// 相对当前元素元素上调用时constuldocument.querySelector(ul);ul.querySelector(li.active);querySelectorAll返回NodeList在多数浏览器实现中为静态列表查询后增删节点不会反映到已有 NodeList与 live 的 HTMLCollection 不同。3.3 遍历与关系属性consteldocument.querySelector(.box);el.parentElement;el.children;// 仅 Element 子节点HTMLCollectionel.childNodes;// 含 Text/CommentNodeListel.nextElementSibling;el.previousElementSibling;el.closest(.wrap);// 向上找匹配选择器的祖先3.4 API 选型建议场景推荐已知 idgetElementById或#idCSS 选择器、复杂匹配querySelector/querySelectorAll需 live 跟踪子元素变化知悉成本后用getElementsBy*或MutationObserver在组件根内查询容器上调用querySelector避免全局扫描四、HTMLCollection vs NodeList对比HTMLCollectionNodeList典型来源getElementsByTagName、childrenquerySelectorAll、childNodes是否 live通常是 livequerySelectorAll为 staticchildNodes等可能 live数组方法较新版本可[...col]、forEach同上面试一句话live 集合在循环中若增删 DOM可能死循环或漏项静态 NodeList 是查询时刻快照constlistdocument.getElementsByTagName(li);console.log(list.length);// 3constnewLidocument.createElement(li);document.querySelector(ul).appendChild(newLi);console.log(list.length);// 4 — live自动更新conststaticListdocument.querySelectorAll(li);// 此后 append 新 listaticList.length 不变实践遍历并删除子节点时用while (el.firstChild) el.removeChild(el.firstChild)或el.replaceChildren()避免 live 集合下标错乱。五、增删改与内容5.1 创建与插入constdivdocument.createElement(div);div.classNamecard;div.textContent安全文本;constuldocument.querySelector(ul);ul.append(div);// 末尾追加ul.prepend(div);// 开头若 div 已在树中会移动ul.insertBefore(div,ul.firstChild);// 批量DocumentFragmentconstfragdocument.createDocumentFragment();for(leti0;i100;i){constlidocument.createElement(li);li.textContenti;frag.appendChild(li);}ul.appendChild(frag);// 一次插入减少重排第 17 篇详述5.2 删除与替换el.remove();// 现代 APIparent.removeChild(el);// 传统el.replaceWith(newEl);el.replaceChildren();// 清空子节点5.3textContentvsinnerHTMLvsinnerTextAPI行为安全/性能textContent纯文本含隐藏元素文本防 XSS不解析 HTMLinnerHTML解析 HTML 字符串用户输入需消毒触发解析innerText近似「可见文本」受 CSS 影响可能触发布局计算el.textContentuserInput;// ✅ 展示用户输入el.innerHTMLuserInput;// ❌ 可能 XSS六、Attribute vs Property6.1 区别Attribute特性Property属性所在HTML 字符串 / DOM 特性层JS 对象上的属性类型多为字符串多为正确类型boolean、numberAPIgetAttribute/setAttributeel.xxx或el[prop]HTML 解析时部分 attribute 会同步到 propertyIDL 属性但二者不一定始终相等。6.2 典型易混例inputidagevalue18disabled/constinputdocument.querySelector(#age);input.getAttribute(value);// 18input.value;// 18propertyinput.value20;input.getAttribute(value);// 可能仍是 18 — 改 property 不总改 attributeinput.disabled;// truebooleaninput.getAttribute(disabled);// 或 disabled存在即可input.removeAttribute(disabled);input.disabled;// falseclassvsclassNameHTML 用classJS 用el.className或el.classListgetAttribute(class)也可。布尔 attributedisabled、checked、selected等存在即 true用 property 读写更自然。6.3data-*与datasetdivdata-user-id42data-roleadmin/divconsteldocument.querySelector(div);el.dataset.userId;// 42camelCaseel.dataset.role;// adminel.dataset.userId43;// 等价于 setAttribute(data-user-id, 43)注意dataset值均为字符串存对象请JSON.stringify。6.4 何时用哪套 API场景建议表单当前值input.valueproperty自定义数据标记data-*/dataset与服务器回显 HTML 一致必要时setAttribute样式类名classList.add/remove/toggle七、动态脚本与 HTML 解析浏览器解析 HTML 时遇到script的默认行为暂停HTML 解析阻塞解析器。下载若src并执行脚本。继续解析。CSS一般不阻塞 DOM 解析但会阻塞渲染避免无样式闪屏 FOUC。7.1async与deferscriptsrca.js/scriptscriptsrcb.jsdefer/scriptscriptsrcc.jsasync/script属性下载执行时机顺序无阻塞解析立即执行文档顺序defer并行下载HTML 解析完成后、DOMContentLoaded前保持顺序async并行下载下载完即执行不保证顺序实践依赖 DOM 且需按序defer独立统计/广告async内联脚本无 defer/async仍阻塞7.2DOMContentLoadedvsloaddocument.addEventListener(DOMContentLoaded,(){// DOM 树就绪可能尚未加载完图片});window.addEventListener(load,(){// 资源图片等大致加载完});八、classList 与样式入门el.classList.add(active);el.classList.remove(hidden);el.classList.toggle(open);el.classList.contains(active);// booleanel.style.colorred;// 行内 stylepropertyel.getAttribute(hidden);// attribute 层复杂样式优先CSS 类少直接改style多项利于维护与批量重排优化。九、速查表需求API按 idgetElementById/#idCSS 选择器querySelector(All)创建元素createElement批量插入DocumentFragment安全设文本textContent表单值.valueproperty自定义标记data-*/dataset类名classList不阻塞解析脚本defer/async十、易混淆点归纳DOM 树 ≠ 渲染树display: none仍在 DOM。HTMLCollection 常 live循环删节点要小心querySelectorAll 为静态。Attribute 是字符串层Property 是 JS 对象层value、checked等优先 property。innerHTML有 XSS 风险用户内容用textContent或消毒库。无 defer/async 的 script 阻塞解析CSS 阻塞渲染不阻塞 DOM 构建。Text 节点也会出现在childNodes中事件 target 可能是文本节点。十一、思考与练习1.getElementsByClassName与querySelectorAll返回集合live 行为有何不同解析前者HTMLCollection 通常 live后者NodeList 为查询快照后续 DOM 变更不更新旧列表。2.用户评论要插入页面用innerHTML还是textContent解析纯文本展示用textContent若必须渲染富文本需白名单过滤如 DOMPurify不可直接innerHTML userInput。3.input.getAttribute(value)与input.value在用户输入后一定相等吗解析不一定。用户改输入后valueproperty已变attribute可能仍是初始 HTML 值。4.三个script defer标签执行顺序解析按文档中出现顺序依次执行在 DOM 解析完成后。5.el.children与el.childNodes区别解析children仅Element子节点HTMLCollectionchildNodes含 Text、Comment 等NodeList。总结DOM是文档的树形对象模型常见节点有Document、Element、Text、DocumentFragment。查询现代优先querySelector(All)理解HTMLCollectionlive与NodeList多为 static。增删改createElement、append、remove、DocumentFragment内容用textContent更安全。Attribute vs Property表单状态、布尔特性用propertydata-*用dataset。脚本默认阻塞解析defer有序延后async下完即跑、无序。下一篇讲DOM 性能与渲染Reflow/Repaint/Composite、强制同步布局、DocumentFragment与渲染流水线。

相关新闻