JavaScripts基础(11)innerHTML、outerHTML、innerText、textContent详解

2,498 阅读4分钟

element.innerHTML

设置或获取HTML语法表示的元素的后代,返回结果字符串

从对象的起始位置到终止位置的全部内容,包括Html标签。

const content = element.innerHTML;
element.innerHTML = htmlString;

设置元素的 innerHTML 将会删除所有该元素的后代并以上面给出的 htmlString 替代

当父元素是 Document 时,设置 innerHTML 将会提示不允许修改

<div id="app">
   <span style="color:red"></span> 好
</div>
var app = document.getElementById('app');
app.innerHTML //"<span style="color:red">你</span> 好 "

显示源码

获取文档当前的 HTML 标记并替换 "<" 字符为 HTML 实体 "&lt;",将 HTML 转换成原始文本,将其包裹在 <pre> 元素中

document.documentElement.innerHTML = "<pre>" +
         document.documentElement.innerHTML.replace(/</g,"&lt;") +
            "</pre>";

给 innerHTML 设置一个值的时候到底发生了什么?

  1. 给定的值被解析为 HTML 或者 XML (取决于文档类型),结果就是 DocumentFragment 对象代表元素新设置的 DOM 节点。
  2. 如果元素内容被替换成 <template>元素,<template> 元素的 content 属性会被替换为步骤1中创建的新的 DocumentFragment
  3. 对于其他所有元素,元素的内容都被替换为新的 DocumentFragment节点。

安全问题

HTML 5 中规定不执行由 innerHTML 插入的<script>标签

但是,有很多不依赖 <script> 标签去执行 JavaScript 的方式

无害情况

const name = "John";
// assuming 'el' is an HTML DOM element
el.innerHTML = name; // harmless in this case

// ...

name = "<script>alert('I am John in an annoying alert!')</script>";
el.innerHTML = name; // harmless in this case

有害情况

const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // shows the alert

解决

当插入纯文本时,使用 Node.textContent代替 innerHTML 。

Node.textContent,它不会把给定的内容解析为 HTML,它仅仅是将原始文本插入给定的位置。

element.outerHTML

获取描述元素(包括其后代)的序列化HTML片段

除了包含innerHTML的全部内容外, 还包含对象标签本身。

获取一个元素的outerHTML属性的值:

// HTML:
/*
<div id="d">
    <p>Content</p>
    <p>Further Elaborated</p>
</div>
*/

const d = document.getElementById("d");
console.log(d.outerHTML);

/*
    字符串 '<div id="d"><p>Content</p><p>Further Elaborated</p></div>'
    被显示到控制台窗口
*/

通过设置outerHTML属性来替换节点:

// HTML:
/*
<div id="container">
    <div id="d">This is a div.</div>
</div>
*/

let container = document.getElementById("container");
let d = document.getElementById("d");

console.log(container.firstChild.nodeName);
// logs "div"

d.outerHTML = "<p>This paragraph replaced the original div.</p>";

console.log(container.firstChild.nodeName);
// logs "P"

/*
    #d div不再是文档树的一部分,新段替换了它。
    (不在页面中显示,但仍然在内存中) 
*/

如果元素没有父元素,即如果它是文档的根元素,则设置其outerHTML属性将抛出一个带有错误代码

document.documentElement.outerHTML = "test";
// 抛出一个 DOMException

虽然元素将在文档中被替换,设置了outerHTML属性的变量仍将保持对原始元素的引用:

let p = document.getElementsByTagName("p")[0];
console.log(p.nodeName);
// 显示: "P"
p.outerHTML = "<div>This div replaced a paragraph.</div>";

console.log(p.nodeName);
// 仍然为: "P";

element.innerText

表示一个节点及其后代的“渲染”文本内容

从起始位置到终止位置的内容, 但它去除Html标签 。

innerText 可操作已被渲染的内容

<div id="app">
   <span style="color:red"></span> 好
</div>
var app = document.getElementById('app');
app.innerText //"你 好 "

Node.textContent

表示一个节点及其后代的文本内容

设置或返回指定节点的文本内容,以及它的所有后代。

let text = someNode.textContent;
someOtherNode.textContent = string;

返回值

  1. 如果节点是一个 document则 textContent 返回 null

如果你要获取整个文档的文本以及 [CDATA data],可以使用 document.documentElement (en-US).textContent

  1. 如果节点是个 [CDATA section]、注释、[processing instruction (en-US)] 或者 [text node],textContent 返回节点内部的文本内容,例如 [Node.nodeValue]
  2. 对于其他节点类型,textContent 将所有子节点的 textContent 合并后返回,除了注释和processing instructions。(如果该节点没有子节点的话,返回一个空字符串。)

与 innerText 的区别

  • textContent 会获取所有元素的内容,包括 [<script>] 和 [<style>]元素,然而 innerText 只返回展示给人看的元素(界面显示的元素)
  • textContent 会返回节点中的每一个元素。相反,innerText 受 CSS 样式的影响,并且不会返回隐藏元素的文本,

由于 innerText 受 CSS 样式的影响,它会触发回流( [reflow] )去确保是最新的计算样式。(回流在计算上可能会非常昂贵,因此应尽可能避免。)

  • 与 textContent 不同的是, 在 Internet Explorer (小于和等于 11 的版本) 中对 innerText 进行修改, 不仅会移除当前元素的子节点,而且还会永久性地破坏所有后代文本节点。在之后不可能再次将节点再次插入到任何其他元素或同一元素中。

与 innerHTML 的区别

[Element.innerHTML]返回 HTM,但是,textContent 通常具有更好的性能,因为文本不会被解析为HTML,使用 textContent 可以防止 XSS 攻击

示例

<div id="divA">This is <span>some</span> text!</div>

let text = document.getElementById('divA').textContent;
// The text variable is now: 'This is some text!'

document.getElementById('divA').textContent = 'This text is different!';
// The HTML for divA is now:
// <div id="divA">This text is different!</div>

兼容到IE9