Javascript Dom操作
<h2 id="1dom-节点类型">1.DOM 节点类型</h2><h3 id="dom文档对象模型将-html-文档表示为一棵树其中每个组成部分都是一个节点node常见的节点类型包括">DOM(文档对象模型)将 HTML 文档表示为一棵树,其中每个组成部分都是一个节点(Node)。常见的节点类型包括:</h3>
<ul>
<li>元素节点(Element Node):如div、p 等标签。</li>
<li>属性节点(Attribute Node):如 id="box"、title="..." 等(注意:在现代 DOM 标准中,属性通常不被视为独立的“子节点”,但可通过 attributes 访问)。</li>
<li>文本节点(Text Node):元素内的文字内容,例如 "我是谁"。</li>
</ul>
<blockquote>
<p>⚠️ 补充说明:虽然“属性节点”在早期 DOM 规范中被定义为一种节点类型(nodeType === 2),但在当前 Web 开发实践中,属性一般通过元素的 getAttribute/setAttribute 等方法操作,而非直接操作属性节点。不过 getAttributeNode() 和 element.attributes 仍可访问它们。</p>
</blockquote>
<h3 id="节点的常用属性">节点的常用属性</h3>
<table>
<thead>
<tr>
<th>属性</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>nodeName</td>
<td>节点的名称(如元素名、#text、#comment 等)</td>
</tr>
<tr>
<td>nodeType</td>
<td>节点的类型(以数字常量表示)</td>
</tr>
<tr>
<td>nodeValue</td>
<td>节点的值(对元素节点恒为 null,对文本节点为文本内容)</td>
</tr>
</tbody>
</table>
<h3 id="nodetype-的常见取值">nodeType 的常见取值</h3>
<pre><code><script>
//依次输出Node对象的属性和值
for(var key in Node){
console.log(key,Node)
//只列出常用的
//ELEMENT_NODE 1 (元素节点)
//ATTRIBUTE_NODE 2 (属性节点)
//TEXT_NODE 3 (文本性节点)
//COMMENT_NODE 8 (注释节点)
//DOCUMENT_NODE 9 (文档节点,即document)
//DOCUMENT_TYPE_NODE 10 (文档类型节点,即<!DOCTYPE html>)
//DOCUMENT_FRAGMENT_NODE 11 (文档片断节点,DocumentFragment)
}
</script>
</code></pre>
<h3 id="各个节点属性值示例">各个节点属性值示例:</h3>
<pre><code><body>
<div id="box" title="我在哪">我是谁</div>
</body>
<script>
// 获取元素节点
var box = document.querySelector('#box')
// 元素节点的属性
console.log(box.nodeName);//DIV
console.log(box.nodeType); //1
console.log(box.nodeValue); //一律为null
// 根据属性名获取单个属性节点
var attrTitle = box.getAttributeNode("title")
// 属性节点的属性
console.log(attrTitle.nodeName);//title
console.log(attrTitle.nodeType); //2
console.log(attrTitle.nodeValue); //"我在哪"
//获取所有的属性节点
var atttibues = box.attributes
//获取特定的节点 下标和属性名都可以获取
var idNode = atttibues.id //atttibues id="box"
console.log(idNode.nodeName,idNode.nodeType,idNode.nodeValue)//id 2 box
// 获取box的文本节点(没有专门的方法用来获取文本节点,但是这个div的第一个子节点就是文本节点)
var textNode = box.childNodes;
// 文本节点的属性
console.log(textNode.nodeName);//#text
console.log(textNode.nodeType); //3
console.log(textNode.nodeValue); //"我是谁"
</script>
</code></pre>
<blockquote>
<p>✅ 关键提示:</p>
<ul>
<li>元素节点的 nodeValue 始终为 null;</li>
<li>文本节点的内容存储在 nodeValue(或等效的 data 属性)中;</li>
<li>属性节点虽存在,但日常开发中更推荐使用 element.getAttribute('attr') 而非操作属性节点本身。</li>
</ul>
</blockquote>
<h2 id="2dom获取">2.Dom获取</h2>
<h3 id="通过选择器拿到的元素列表有2类nodelist和htmlcollection区别如下">通过选择器拿到的元素列表有2类:NodeList和HTMLCollection,区别如下:</h3>
<table>
<thead>
<tr>
<th>特性</th>
<th>NodeList</th>
<th>HTMLCollection</th>
</tr>
</thead>
<tbody>
<tr>
<td>包含的节点类型</td>
<td>任意 Node(包括元素、文本、注释等)</td>
<td>仅 HTML 元素节点(Element)</td>
</tr>
<tr>
<td>是否动态(live)</td>
<td>通常静态(但有例外)</td>
<td>总是动态(live)</td>
</tr>
<tr>
<td>是否有数组方法(如 map, forEach)</td>
<td>有(现代浏览器支持 forEach 等)</td>
<td>❌ 没有(不是可迭代对象,除非手动转)</td>
</tr>
<tr>
<td>能否用 for...of 遍历</td>
<td>✅ 可以(现代环境)</td>
<td>✅ 可以(现代浏览器也实现了 Symbol.iterator)</td>
</tr>
<tr>
<td>典型获取方式</td>
<td>querySelectorAll, childNodes</td>
<td>getElementsBy* 系列</td>
</tr>
</tbody>
</table>
<h3 id="htmlcollection">HTMLCollection</h3>
<ul>
<li>只包含 Element 节点(比如 div, p),自动过滤掉文本、注释等。</li>
<li>是“动态集合”(live collection):</li>
<li>如果 DOM 发生变化(比如新增/删除匹配的元素),HTMLCollection 会自动更新。</li>
<li>没有数组原型方法(如 map, filter),但可以用 Array.from() 或展开运算符转换。</li>
</ul>
<h3 id="nodelist">NodeList</h3>
<ul>
<li>可以包含任何类型的 Node(元素、文本节点、注释等)。</li>
<li>分为两种:
<ul>
<li>静态 NodeList:如 querySelectorAll() 返回的 —— 不会随 DOM 变化而更新。</li>
<li>动态 NodeList:如 childNodes 返回的 —— 会随 DOM 更新(这是少数例外!)。</li>
</ul>
</li>
</ul>
<h3 id="静态-vs-动态-示例">静态 vs 动态 示例</h3>
<pre><code><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<style>
*{padding: 0;margin: 0;}
</style>
<body>
<ul>
<li class="test">1</li>
<li class="test">2</li>
<li class="test">3</li>
<li class="test">4</li>
</ul>
</body>
</html>
<script>
var lis = document.getElementsByTagName('li')
var liByQuery = document.querySelectorAll('li')
console.log(lis.length)// 4
console.log(liByQuery.length)// 4
// 动态添加li标签
document.querySelector('ul').innerHTML += "<li class='test'>5</li>"
console.log(lis.length) // 5
console.log(liByQuery.length) // 4
</script>
</code></pre>
<h3 id="遍历nodelist可以使用foreach遍历而htmlcollection没有foreach方法只能使用for循环遍历">遍历:NodeList,可以使用foreach()遍历,而HTMLCollection没有forEach方法,只能使用for循环遍历</h3>
<pre><code><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=2.0">
<title>Test</title>
</head>
<body>
<ul>
<li class="test">1</li>
<li class="test">2</li>
<li class="test">3</li>
<li class="test">4</li>
</ul>
</body>
</html>
<script>
var li = document.getElementsByTagName('li')
var li2 = document.getElementsByClassName('test')
var li3 = document.querySelectorAll('li')
var li4 = document.querySelector('ul').children
console.log(li) // HTMLCollection(4)
console.log(li2) // HTMLCollection(4)
console.log(li3) // NodeList(4)
console.log(li4) // HTMLCollection(4)
</script>
</code></pre>
<h2 id="3子元素-vs-子节点">3.子元素 vs 子节点</h2>
<table>
<thead>
<tr>
<th>属性</th>
<th>说明</th>
<th>返回类型</th>
</tr>
</thead>
<tbody>
<tr>
<td>children</td>
<td>获取当前 DOM 元素的所有子元素(仅元素节点)</td>
<td>HTMLCollection</td>
</tr>
<tr>
<td>firstElementChild</td>
<td>获取第一个子元素(等价于 children)</td>
<td>Element</td>
</tr>
<tr>
<td>lastElementChild</td>
<td>获取最后一个子元素(等价于 children)</td>
<td>Element</td>
</tr>
<tr>
<td>childElementCount</td>
<td>返回子元素的数量(等价于 children.length)</td>
<td>number</td>
</tr>
<tr>
<td>childNodes</td>
<td>获取当前 DOM 元素的所有子节点(包括元素节点、文本节点、注释节点等,不包含属性节点)</td>
<td>NodeList</td>
</tr>
<tr>
<td>firstChild</td>
<td>获取第一个子节点(等价于 childNodes)</td>
<td>Node</td>
</tr>
<tr>
<td>lastChild</td>
<td>获取最后一个子节点(等价于 childNodes)</td>
<td>Node</td>
</tr>
</tbody>
</table>
<blockquote>
<p>💡 关键区别:</p>
<ul>
<li>“子元素”仅指 标签 这类 HTML 元素节点;</li>
<li>“子节点”包含所有类型的节点,例如换行、空格产生的文本节点(#text)。</li>
</ul>
</blockquote>
<h3 id="示例代码">示例代码:</h3>
<pre><code><body>
<div id="app">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
</body>
<script>
var ul = document.querySelector('ul')
//子元素
console.log(ul.children) //HTMLCollection(4)
//子元素数量
console.log(ul.childElementCount) //4
console.log(ul.children.length) //4
//第一个子元素(等价)
console.log(ul.children === ul.firstElementChild) //true
//最后一个子元素(等价)
console.log(ul.children === ul.lastElementChild) //true
//子节点(把代码回车换行当作文本节点也算进去了)
console.log(ul.childNodes) //NodeList(9)
//第一个子节点
console.log(ul.firstChild) //#text
//等价
console.log(ul.childNodes === ul.firstChild) //true
console.log(ul.childNodes === ul.lastChild) //true
</script>
</code></pre>
<blockquote>
<p>📌 注意:<br>
在 HTML 源码中,标签之间的换行符和空格会被解析为文本节点(Text Node),因此 childNodes 的长度通常比 children 大。若想避免干扰,可使用压缩后的 HTML(无多余空白),或始终优先使用 children / firstElementChild 等“仅元素”接口。</p>
</blockquote>
<h2 id="4父元素与父节点">4.父元素与父节点</h2>
<table>
<thead>
<tr>
<th>属性 / 方法</th>
<th>说明</th>
<th>调用者</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>parentElement</td>
<td>获取当前 DOM 元素的父元素节点(仅限 Element 类型)</td>
<td>任意 Element</td>
<td>若父节点不是元素(如文档片段、文档根等),返回 null</td>
</tr>
<tr>
<td>parentNode</td>
<td>获取当前 DOM 节点的父节点(可以是任意 Node 类型)</td>
<td>任意 Node</td>
<td>总是返回实际的父节点(可能是 Element、Document、DocumentFragment 等)</td>
</tr>
<tr>
<td>closest(selector)</td>
<td>从当前元素向上遍历祖先树,返回第一个匹配指定 CSS 选择器的祖先元素</td>
<td>任意 Element</td>
<td>若未找到则返回 null;选择器参数不能为空</td>
</tr>
</tbody>
</table>
<blockquote>
<p>💡 关键区别:</p>
<ul>
<li>parentNode 是所有节点都有的属性,返回的是直接父节点(类型不限);</li>
<li>parentElement 是 Element 接口的属性,只在父节点是元素时才返回它,否则返回 null。</li>
<li>在普通 HTML 文档中,绝大多数元素的父节点本身就是元素(如 li 的父是 ul),所以两者通常相等;</li>
<li>但在特殊场景(如操作 DocumentFragment、 的父是 document 等)下,二者结果可能不同。</li>
</ul>
</blockquote>
<h3 id="示例代码-1">示例代码:</h3>
<pre><code><body>
<div id="app">
<div class="box">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
</div>
</body>
<script>
//父元素
var ul = document.querySelector('ul')
//第一个子元素
var li = document.querySelector('ul > li')
//等价
console.log(ul === li.parentElement) //true
console.log(ul === li.parentNode) //true
//最近的祖先元素
console.log(li.closest('.box')) //div.box
</script>
</code></pre>
<h2 id="5兄弟元素与兄弟节点">5.兄弟元素与兄弟节点</h2>
<table>
<thead>
<tr>
<th>属性</th>
<th>说明</th>
<th>调用者</th>
</tr>
</thead>
<tbody>
<tr>
<td>previousElementSibling</td>
<td>获取当前元素的前一个兄弟元素节点(仅限 Element 类型)</td>
<td>当前 DOM 元素</td>
</tr>
<tr>
<td>nextElementSibling</td>
<td>获取当前元素的后一个兄弟元素节点(仅限 Element 类型)</td>
<td>当前 DOM 元素</td>
</tr>
<tr>
<td>previousSibling</td>
<td>获取当前节点的前一个兄弟节点(可能是元素、文本、注释等)</td>
<td>当前 DOM 节点</td>
</tr>
<tr>
<td>nextSibling</td>
<td>获取当前节点的后一个兄弟节点(可能是元素、文本、注释等)</td>
<td>当前 DOM 节点</td>
</tr>
</tbody>
</table>
<blockquote>
<p>💡 关键区别:</p>
<ul>
<li>带 Element 的属性只返回元素节点,自动跳过文本、注释等;</li>
<li>不带 Element 的属性返回所有类型的兄弟节点,包括 HTML 源码中的空白字符生成的文本节点(#text)</li>
</ul>
</blockquote>
<h3 id="示例代码-2">示例代码:</h3>
<pre><code><body>
<div id="app">
<ul>
<li id="li1">1</li>
<li id="li2">2</li>
<li id="li3">3</li>
<li id="li4">4</li>
</ul>
</div>
</body>
<script>
const li1 = document.querySelector('#li1');
const li2 = document.querySelector('#li2');
const li3 = document.querySelector('#li3');
const li4 = document.querySelector('#li4');
// —— 兄弟元素(仅元素节点) ——
console.log(li2.previousElementSibling === li1); // true
console.log(li2.nextElementSibling === li3); // true
// —— 兄弟节点(包含空白文本节点) ——
console.log(li2.previousSibling); // #text(位于 <li1> 和 <li2> 之间的换行+缩进)
console.log(li2.nextSibling); // #text(位于 <li2> 和 <li3> 之间的换行+缩进)
// 验证节点类型
console.log(li2.previousSibling.nodeType === Node.TEXT_NODE); // true
console.log(li2.previousSibling.nodeValue.trim() === ''); // true(内容为空白)
</script>
</code></pre>
<h2 id="6添加元素">6.添加元素</h2>
<p>DOM 提供了多种方式向文档中插入新节点,主要分为两类:作为子元素插入 和 作为兄弟节点插入</p>
<h3 id="作为子元素插入">作为子元素插入</h3>
<table>
<thead>
<tr>
<th>方法</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>parent.appendChild(child)</td>
<td>将 child 作为 parent 的最后一个子节点插入</td>
</tr>
<tr>
<td>parent.insertBefore(newNode, referenceNode)</td>
<td>将 newNode 插入到 parent 中的 referenceNode 之前</td>
</tr>
</tbody>
</table>
<h3 id="示例代码-3">示例代码</h3>
<pre><code><body>
<ul>
<li>1</li>
<li id="test">2</li>
<li>3</li>
</ul>
</body>
</html>
<script>
const ul = document.querySelector('ul');
// 创建新 <li> 并追加到末尾
const li4 = document.createElement('li');
li4.textContent = '4'; // 推荐使用 textContent 而非 innerHTML(防 XSS)
ul.appendChild(li4);
// 创建另一个 <li> 并插入到 #test 之前
const liLife = document.createElement('li');
liLife.textContent = 'life';
const liTest = document.querySelector('#test');
ul.insertBefore(liLife, liTest);
</script>
</code></pre>
<h3 id="运行结果">运行结果</h3>
<pre><code><ul>
<li>1</li>
<li>life</li>
<li id="test">2</li>
<li>3</li>
<li>4</li>
</ul>
</code></pre>
<h3 id="作为兄弟节点插入现代-api">作为兄弟节点插入(现代 API)</h3>
<table>
<thead>
<tr>
<th>方法</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>node.before(...nodes)</td>
<td>在 node 之前插入一个或多个节点(可为元素、文本等)</td>
</tr>
<tr>
<td>node.after(...nodes)</td>
<td>在 node 之后插入一个或多个节点</td>
</tr>
</tbody>
</table>
<blockquote>
<p>⚠️ IE 不支持,但现代浏览器(Chrome、Firefox、Safari、Edge)均已支持</p>
</blockquote>
<h3 id="示例代码-4">示例代码</h3>
<pre><code><body>
<div id="app">
<ul>
<li id="li1">1</li>
<li id="li2">2</li>
<li id="li3">3</li>
</ul>
</div>
</body>
<script>
// 在 #li1 前插入新 <li>
const li0 = document.createElement('li');
li0.id = 'li0';
li0.textContent = '0';
document.querySelector('#li1').before(li0);
// 在 #li3 后插入新 <li>
const li4 = document.createElement('li');
li4.id = 'li4';
li4.textContent = '4';
document.querySelector('#li3').after(li4);
// 也可以直接插入文本(虽然较少用)
// li0.before('⚠️ '); // 会在 li0 前插入一个文本节点
</script>
</code></pre>
<h3 id="运行结果-1">运行结果</h3>
<pre><code><ul>
<li id="li0">0</li>
<li id="li1">1</li>
<li id="li2">2</li>
<li id="li3">3</li>
<li id="li4">4</li>
</ul>
</code></pre>
<h2 id="7移除与替换元素">7.移除与替换元素</h2>
<p>DOM 提供了多种方式来移除或替换节点,分为两类操作:通过父节点操作子节点(传统方式)和节点自我操作(现代方式)</p>
<h3 id="传统方式通过父节点">传统方式(通过父节点)</h3>
<table>
<thead>
<tr>
<th>方法</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>parent.removeChild(child)</td>
<td>从 parent 中移除指定的子节点 child</td>
</tr>
<tr>
<td>parent.replaceChild(newNode, oldNode)</td>
<td>用 newNode 替换 parent 中的 oldNode</td>
</tr>
</tbody>
</table>
<blockquote>
<p>✅ 这些方法兼容性极好,适用于所有浏览器(包括 IE)</p>
</blockquote>
<h3 id="现代方式节点自我操作">现代方式(节点自我操作)</h3>
<table>
<thead>
<tr>
<th>方法</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>node.remove()</td>
<td>移除自身(无需通过父节点)</td>
</tr>
<tr>
<td>node.replaceWith(...nodes)</td>
<td>用一个或多个新节点替换自身</td>
</tr>
</tbody>
</table>
<blockquote>
<p>IE 不支持,但在 Chrome、Firefox、Safari、Edge 等现代浏览器中已广泛支持</p>
</blockquote>
<h3 id="示例代码-5">示例代码</h3>
<pre><code><body>
<div id="app">
<ul>
<li id="li1">1</li>
<li id="li2">2</li>
<li id="li3">3</li>
</ul>
</div>
</body>
<script>
const ul = document.querySelector('ul');
const li1 = document.querySelector('#li1');
const li2 = document.querySelector('#li2');
const li3 = document.querySelector('#li3');
// —— 移除元素 ——
li1.remove(); // 方式1:自我移除(现代)
ul.removeChild(li2); // 方式2:通过父节点移除(传统)
// —— 替换元素 ——
const newLi = document.createElement('li');
newLi.textContent = 'replaced li'; // 推荐使用 textContent 防 XSS
ul.replaceChild(newLi, li3); // 方式1:通过父节点替换(传统)
// 或者(如果 li3 还存在):
// li3.replaceWith(newLi); // 方式2:自我替换(现代)
</script>
</code></pre>
<h3 id="运行结果第一第二个被移除第三个被替换">运行结果:(第一,第二个被移除,第三个被替换)</h3>
<pre><code><ul>
<li>replaced li</li>
</ul>
</code></pre>
<h2 id="8复制-dom-元素">8.复制 DOM 元素</h2>
<h3 id="使用-elementclonenode-可复制一个-dom-节点">使用 element.cloneNode() 可复制一个 DOM 节点:</h3>
<table>
<thead>
<tr>
<th>调用方式</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>cloneNode(true)</td>
<td>深拷贝:复制元素本身、属性及其所有后代节点(包括子元素和文本)</td>
</tr>
<tr>
<td>cloneNode(false) 或 cloneNode()</td>
<td>浅拷贝:仅复制元素本身和属性,不包含任何子节点(如文本、子标签等)</td>
</tr>
</tbody>
</table>
<blockquote>
<p>坑爹的W3C不解释,查文档只推荐MDN</p>
</blockquote>
<h3 id="示例代码-6">示例代码</h3>
<pre><code><body>
<div id="app">
<ul>
<li class="text-align">hello world</li>
</ul>
</div>
</body>
<script>
const ul = document.querySelector('ul');
const li = document.querySelector('li');
// 两次浅拷贝(不带子节点)
ul.appendChild(li.cloneNode()); // 等价于 cloneNode(false)
ul.appendChild(li.cloneNode(false));
// 一次深拷贝(带子节点,包括文本)
ul.appendChild(li.cloneNode(true));
</script>
</code></pre>
<h3 id="运行结果可以看出第二第三都是浅拷贝而来没有带上子节点">运行结果:(可以看出,第二第三都是浅拷贝而来,没有带上子节点)</h3>
<pre><code><li class="text-align">hello world</li><!-- 原始节点 -->
<li class="text-align"></li> <!-- 浅拷贝 1 -->
<li class="text-align"></li> <!-- 浅拷贝 2 -->
<li class="text-align">hello world</li><!-- 深拷贝 -->
</code></pre>
<h3 id="补充说明">补充说明</h3>
<ul>
<li>cloneNode() 不会复制通过 addEventListener 添加的事件监听器;</li>
<li>若元素有 id 属性,克隆后会产生重复 ID,需手动处理;</li>
</ul>
<h2 id="9滚动到目标元素所在位置">9.滚动到目标元素所在位置</h2>
<p>有两种常用方式可让页面(或可滚动容器)自动滚动到某个元素的位置:</p>
<h3 id="使用锚点链接html-原生方式">使用锚点链接(HTML 原生方式)</h3>
<p>通过 a 标签的 href 属性指向目标元素的 id(格式为 #id),点击后浏览器会自动滚动到该元素</p>
<pre><code><body>
<div>
<!-- 使用a链接进行滚动 -->
<a href="#box3">滚动到3</a>
</div>
<div class="box" id="box1">1</div>
<div class="box" id="box2">2</div>
<div class="box" id="box3">3</div>
</body>
</code></pre>
<blockquote>
<p>✅ 优点:无需 JavaScript,语义清晰,支持浏览器历史记录(可后退);</p>
</blockquote>
<h3 id="使用-elementscrollintoviewjavascript-方式">使用 element.scrollIntoView()(JavaScript 方式)</h3>
<p>调用元素的 scrollIntoView() 方法,可编程控制滚动行为</p>
<h4 id="基础用法">基础用法</h4>
<pre><code><button>滚动到 #box3</button>
<div class="box" id="box1">1</div>
<div class="box" id="box2">2</div>
<div class="box" id="box3">3</div>
<script>
const btn = document.querySelector('button');
btn.onclick = function () {
const box3 = document.querySelector('#box3');
box3.scrollIntoView(); // 默认平滑滚动到视口顶部(行为因浏览器而异)
};
</script>
</code></pre>
<h4 id="高级用法推荐">高级用法(推荐)</h4>
<p>scrollIntoView() 支持传入配置对象,精确控制滚动行为:</p>
<pre><code>box3.scrollIntoView({
behavior: 'smooth',// 滚动动画:'auto'(默认,瞬间跳转)或 'smooth'(平滑滚动)
block: 'start', // 垂直对齐:'start' | 'center' | 'end' | 'nearest'
inline: 'nearest' // 水平对齐(对行内元素或横向滚动有用)
});
</code></pre>
<blockquote>
<p>⚠️ 兼容性:behavior: 'smooth' 在 IE 中不支持,但现代浏览器(Chrome ≥61, Firefox ≥36, Safari ≥15.4)均已支持</p>
</blockquote>
<h2 id="10获取与设置标签内容">10.获取与设置标签内容</h2>
<p>DOM 提供了多种方式读取或修改元素的内容,它们的行为差异显著:</p>
<table>
<thead>
<tr>
<th>属性</th>
<th>说明</th>
<th>是否解析 HTML</th>
<th>是否包含隐藏内容</th>
<th>是否保留格式/空白</th>
</tr>
</thead>
<tbody>
<tr>
<td>el.innerHTML</td>
<td>获取/设置元素内部的 HTML 字符串</td>
<td>✅ 是(赋值时会渲染标签)</td>
<td>✅ 包含注释、隐藏元素等所有子节点</td>
<td>✅ 保留原始 HTML 格式(包括换行、缩进)</td>
</tr>
<tr>
<td>el.outerHTML</td>
<td>获取/设置元素自身及其内部的完整 HTML 字符串</td>
<td>✅ 是</td>
<td>✅ 同 innerHTML,但包含当前标签本身</td>
<td>✅ 保留完整结构</td>
</tr>
<tr>
<td>el.textContent</td>
<td>获取/设置元素内所有文本节点的拼接结果(纯文本)</td>
<td>❌ 否(赋值时 < 不会被解析为标签)</td>
<td>✅ 包含隐藏元素、注释中的文本(注释文本不可见,但 textContent 不包含注释内容!)</td>
<td>✅ 保留所有空白字符(包括换行、缩进)</td>
</tr>
<tr>
<td>el.innerText</td>
<td>获取元素内用户可见的文本内容</td>
<td>❌ 否</td>
<td>❌ 忽略 display: none、visibility: hidden 等不可见文本</td>
<td>❌ 按视觉渲染结果处理空白(类似用户复制粘贴的效果)</td>
</tr>
</tbody>
</table>
<h3 id="代码示例">代码示例</h3>
<pre><code><body>
<div class="box">
<span style="display: none;">
隐藏文本
</span>
<!-- 注释 -->
<span>
123
</span>
<span>
456
</span>
<div>
另一行
</div>
</div>
</body>
<script>
var box = document.querySelector('.box')
console.log('---innerHTML---')
console.log(box.innerHTML)
console.log('---textContent---')
console.log(box.textContent)
console.log('---innerText---')
console.log(box.innerText)
</script>
</code></pre>
<p><img src="https://img2024.cnblogs.com/blog/1813302/202405/1813302-20240519175250296-1135320850.png"></p><br><br>
来源:https://www.cnblogs.com/OrochiZ-/p/11570079.html
頁:
[1]