跳到主要内容

深入理解 element.innerHTML

设置和获取元素的 HTML 内容

innerHTML 属性用于设置或获取元素的 HTML 内容。以下是一个基本示例:

<div class="wrapper"></div>
<script>
const wrapperElement = document.getElementsByClassName('wrapper')[0];
wrapperElement.innerHTML = '<h1>Hello World</h1>';
</script>

需要注意以下几点:

innerHTML 字符串必须符合有效的 HTML 语法,否则在旧版本浏览器中可能会出现语法错误。

document.innerHTML 是只读属性,无法直接修改整个文档的 HTML。

innerHTML 赋值会移除元素原有的所有子节点,并用新的 HTML 内容替换。

显示 HTML 源码

有时需要在页面上展示 HTML 源码,可以结合 innerHTML 和字符串替换实现:

<div class="wrapper"></div>
<script>
const wrapperElement = document.getElementsByClassName('wrapper')[0];
const htmlContent = document.documentElement.innerHTML;
const encodedHtml = htmlContent.replace(/</g, '&lt;');

document.documentElement.innerHTML = '<pre>' + encodedHtml + '</pre>';
wrapperElement.innerHTML = encodedHtml;
</script>

上述代码首先获取整个文档的 HTML,然后将 < 替换为 &lt; 以进行转义,最后使用 <pre> 标签包裹并设置回去,从而在页面上显示格式化后的 HTML 源码。

引用失效问题

使用 innerHTML 赋值后,之前保存的 DOM 元素引用可能会失效。如下例所示:

<div class="wrapper">
<span>Hello</span>
</div>
<script>
const wrapperElement = document.getElementsByClassName('wrapper')[0];
const textElement = document.getElementsByTagName('span')[0];

wrapperElement.innerHTML += '<h1>World</h1>';
textElement.style.color = 'red'; // Error!
</script>

引用失效示意图

innerHTML 操作会破坏对原有 DOM 结构的引用。上面的代码中,textElementinnerHTML 修改后失效,继续使用会报错。

解决引用失效的方法

可以先使用 innerHTML 修改内容,然后重新获取元素引用:

const wrapperElement = document.getElementsByClassName('wrapper')[0];
wrapperElement.innerHTML += '<h1>World</h1>';

const textElement = document.getElementsByTagName('span')[0];
textElement.style.color = 'red'; // OK

element.outerHTML

innerHTML 类似,outerHTML 可以替换元素本身及其所有子节点:

wrapperElement.outerHTML = '<div>Replaced</div>';

设置 innerHTML 的原理

执行 element.innerHTML = '<h1>title</h1>' 时,大致经历以下步骤:

  1. 浏览器解析 '<h1>title</h1>' 字符串为 HTML 文档结构。
  2. 使用 DocumentFragment 将解析后的 HTML 转换为 DOM 节点。
  3. 替换元素原有的所有子节点。

由于涉及 HTML 解析和大量 DOM 操作,innerHTML 的执行速度较慢,应谨慎使用。

安全问题

现代浏览器出于安全考虑,会阻止通过 innerHTML 插入的 <script> 标签执行:

const content = '123';
wrapperElement.innerHTML = '<script>alert("Hi")</script>';
wrapperElement.innerHTML = content; // 不会弹出 alert

然而,通过其他方式插入的恶意代码仍可能带来安全隐患:

const content = '<img src="x" onerror="alert(\'Hacked!\')" />';
wrapperElement.innerHTML = content; // 会执行 alert

因此,避免使用 innerHTML 插入不可信的内容,以防范 XSS 攻击。

使用建议

插入纯文本内容时,建议使用 Node.textContent 代替 innerHTMLtextContent 仅插入文本内容,不解析 HTML 标签,执行效率更高,且更安全:

wrapperElement.textContent = 'Hello <b>World</b>!';

需要动态创建 DOM 元素时,建议使用 document.createElement 等底层 API 代替字符串拼接:

const divElement = document.createElement('div');
divElement.innerHTML = '<h1>Hello World</h1>';
document.body.appendChild(divElement);

HTMLElement.innerText

innerText 用于设置或获取元素的渲染文本内容。

与 textContent 的区别

textContent 获取元素的所有文本内容,包括 <script><style> 等特殊标签中的内容。

innerText 仅获取用户可见的内容,受 CSS 样式影响。此外,读取 innerText 时,浏览器需重新计算渲染结果,性能较差。

<div class="wrapper">
<h1>标题</h1>
<p class="content">
<style>
.content {
color: orange;
}
</style>
可见内容
<br />
可见内容
<span style="display: none;">不可见内容</span>
</p>
</div>

<script>
const wrapper = document.querySelector('.wrapper');
console.log(wrapper.innerText);
// 输出:
// 标题
// 可见内容
// 可见内容

console.log(wrapper.textContent);
// 输出:
// 标题
//
// .content { color: orange; }
//
// 可见内容
//
// 可见内容
// 不可见内容
</script>