转载

获取 DOM 内容的 API 接口

Web 开发者可能会使用 jQuery .html().text() 方法来设置 DOM 内容,但他们的实现仍然依赖于 DOM API。 本文来梳理一下这些用来获取 DOM 内容的 DOM 属性(attribute), 比较它们的区别: innerHTML , outerHTML , innerText , outerText , text , textContent , 以及 jQuery 中 .html().text() 的实现。

innerHTML/outerHTML

outerHTMLinnerHTML DOM 属性用来设置 DOM 的 HTML 内容。 其中 innerHTML 返回元素内容的 HTML 片段,而 outerHTML 返回的 HTML 片段则包括元素本身、以及元素内容的。 其中 innerH 常常用于清空元素内容。

document.body.innerHTML = '';

需要注意 innerHTMl 设置的脚本内容将不会被执行,参考 在 DOM 中动态插入并执行脚本 。

innerText/outerText

innerHTML , outerHTML 相同,inner 只会设置内容而 outer 会更改整个元素。 不同的是, innerTextouterText 则用来获取和设置渲染后的结果。 例如设置的 HTML 特殊字符会被转义,换行会被解析为 <br/> 。例如:

document.body.innerText = '<h2>header</h2>/nparagraph'

的渲染结果为:

<h2>header</h2><br>paragraph

利用 innerText 可以方便地进行 HTML 转义:

function escape(str){
  var el = document.createElement('div');
  el.innerText = str;
  return el.innerHTML;
}

// 返回 <h2 id="foo">
escape('<h2 id="foo">');

text/textContent

textContentinnerText 表现相似,但有一些细节不同:

  • textContent 是定义在 Node 上的,Element 继承了该属性。
  • textContent 可以获取不渲染的内容而 innerText 不可以。包括 <style> , <script> , 以及被 CSS 隐藏的元素。
  • innerText 排除了隐藏元素,它会引起重排(Reflow)。
  • IE11 及以下的 innerText 会销毁被移除的元素,而 textContent 不会。

text 只在特定的几个元素上有定义,比如 <a><script>

  • <a> 元素的 text 用来设置其文本内容。其表现完全等同于 textContent :

    The text IDL attribute, on getting, must return the same value as the textContent IDL attribute on the element, and on setting, must act as if the textContent IDL attribute on the element had been set to the new value. – W3C HTML5

  • <script> 元素的 text 用来设置其脚本的内容,这时完全等同于 textContent , innerText , innerHTML

jQuery .html()

jQuery 的 .html() 用来设置 HTML 元素的 HTML 内容。 不同于 innherHTML ,jQuery 的 .html() 会执行字符串中的脚本。 几乎所有操作 DOM 内容的 jQuery 方法都有这一行为,包括 .after() , .append() , .before() 等等。

当然这不是 Magic,jQuery 在设置 innerHTML 的同时,找到了里面所有的 <script> 并进行强制加以执行。 在 .html() 的定义在 /src/manipulation.js 中, 它调用了 .append() 来进行进行 DOM 操作,最终调用到 domManip( collection, args, callback, ignored ) 函数:

function domManip( collection, args, callback, ignored ) {
    // ...
    if ( hasScripts ) {
        // ...
        if ( node.src ) {
            // Optional AJAX dependency, but won't run scripts if not present
            if ( jQuery._evalUrl ) {
                jQuery._evalUrl( node.src );
            }
        } else {
            DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
        }
    }
}

这里调用了 DOMEval 来强制执行脚本,其代码在 /src/core/DOMEval.js 中:

function DOMEval( code, doc ) {
    doc = doc || document;

    var script = doc.createElement( "script" );

    script.text = code;
    doc.head.appendChild( script ).parentNode.removeChild( script );
}

.appendChild() 并立即 .removeChild() 会导致立即执行(以及必要的下载)脚本。对于动态执行脚本在 DOM 中动态插入并执行脚本 一文有详细讨论。

jQuery .text()

jQuery .text() 就非常简单,它的实现只有 11 行, 使用的 DOM API 正是上文中讨论的 textContent

text: function( value ) {
    return access( this, function( value ) {
        return value === undefined ?
            jQuery.text( this ) :
            this.empty().each( function() {
                if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
                    this.textContent = value;
                }
            } );
    }, null, value, arguments.length );
},

扩展阅读

  • http://stackoverflow.com/questions/24427621/innertext-vs-innerhtml-vs-label-vs-text-vs-textcontent-vs-outertext
  • https://w3c.github.io/DOM-Parsing/
  • https://www.w3.org/TR/html5/single-page.html
  • https://github.com/jquery/jquery
原文  http://harttle.com/2017/01/29/dom-content-interface.html
正文到此结束
Loading...