执行 innerHTML 里的 <script>

230 阅读1分钟

执行 innerHTML 里的 <script>

之前在做公司的一个抽奖模板的需求时遇到了 innerHTML 里的 <script>标签不执行的情况,即脚本不被解析。

appendChild

appendChild 把<script>标签直接塞进页面是可以执行和加载里面的 js 的,我们需要做的就只是把所有的<script>找出来,然后通过 appendChild 塞到页面里,需要注意的是script的加载和执行并非是同步的。为了流程的控制,在执行 js 的时候,可以使用 promise 来控制(Promise.reduce)

JQuery.html()

jQuery 会对代码进行正则判断,符合条件就会使用jQuery的append

// rnoInnerhtml 的值
rnoInnerhtml = /<script|<style|<link/i

// html()
html: function( value ) {
  return access( this, function( value ) {
    var elem = this[ 0 ] || {},
      i = 0,
      l = this.length;

    if ( value === undefined && elem.nodeType === 1 ) {
      return elem.innerHTML;
    }

    // See if we can take a shortcut and just use innerHTML
    if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
      !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {

      value = jQuery.htmlPrefilter( value );

      try {
        for ( ; i < l; i++ ) {
          elem = this[ i ] || {};

          // Remove element nodes and prevent memory leaks
          if ( elem.nodeType === 1 ) {
            jQuery.cleanData( getAll( elem, false ) );
            elem.innerHTML = value;
          }
        }

        elem = 0;

      // If using innerHTML throws an exception, use the fallback method
      } catch ( e ) {}
    }

    if ( elem ) {
      this.empty().append( value );
    }
  }, null, value, arguments.length );
}

createContextualFragment

该方法通过调用HTML片段解析算法或XML片段解析算法返回一个文档片段

let range = document.createRange();
// make the parent of the first div in the document becomes the context node
range.selectNode(document.body);
let documentFragment = range.createContextualFragment(innerHtml);
document.body.appendChild(documentFragment)

重新触发DOMContentLoaded

let DOMContentLoadedEvent = document.createEvent('Event');
DOMContentLoadedEvent.initEvent('DOMContentLoaded', true, true);
document.dispatchEvent(DOMContentLoadedEvent);