我尝试在<div>上使用innerHTML加载一些脚本到页面中。脚本似乎加载到DOM中,但它从未执行(至少在Firefox和Chrome中)。有一种方法让脚本执行时插入他们与innerHTML?

示例代码:

<!DOCTYPE html > < html > <身体onload = " . getelementbyid(机)。innerHTML = '<script>alert(\'hi\')<\/script>'"> 难道不应该出现“hi”的提醒吗? < div id = "装载机" > < / div > 身体< / > < / html >


当前回答

这里的解决方案不使用eval,与脚本、链接脚本以及模块一起工作。

该函数接受3个参数:

要插入的html代码的字符串 Dest:目标元素的引用 Append:在目标元素HTML的末尾启用追加的布尔标志

function insertHTML(html, dest, append=false){
    // if no append is requested, clear the target element
    if(!append) dest.innerHTML = '';
    // create a temporary container and insert provided HTML code
    let container = document.createElement('div');
    container.innerHTML = html;
    // cache a reference to all the scripts in the container
    let scripts = container.querySelectorAll('script');
    // get all child elements and clone them in the target element
    let nodes = container.childNodes;
    for( let i=0; i< nodes.length; i++) dest.appendChild( nodes[i].cloneNode(true) );
    // force the found scripts to execute...
    for( let i=0; i< scripts.length; i++){
        let script = document.createElement('script');
        script.type = scripts[i].type || 'text/javascript';
        if( scripts[i].hasAttribute('src') ) script.src = scripts[i].src;
        script.innerHTML = scripts[i].innerHTML;
        document.head.appendChild(script);
        document.head.removeChild(script);
    }
    // done!
    return true;
}

其他回答

尝试使用template和document.importNode。这里有一个例子:

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Sample</title> </head> <body> <h1 id="hello_world">Sample</h1> <script type="text/javascript"> var div = document.createElement("div"); var t = document.createElement('template'); t.innerHTML = "Check Console tab for javascript output: Hello world!!!<br/><script type='text/javascript' >console.log('Hello world!!!');<\/script>"; for (var i=0; i < t.content.childNodes.length; i++){ var node = document.importNode(t.content.childNodes[i], true); div.appendChild(node); } document.body.appendChild(div); </script> </body> </html>

使用$(parent).html(code)代替parent。innerHTML = code。

下面还修复了使用document的脚本。通过SRC属性写入和加载脚本。不幸的是,即使这并不工作与谷歌AdSense脚本。

var oldDocumentWrite = document.write;
var oldDocumentWriteln = document.writeln;
try {
    document.write = function(code) {
        $(parent).append(code);
    }
    document.writeln = function(code) {
        document.write(code + "<br/>");
    }
    $(parent).html(html); 
} finally {
    $(window).load(function() {
        document.write = oldDocumentWrite
        document.writeln = oldDocumentWriteln
    })
}

简单,没有eval,没有函数:

    fetch('/somepage')
    .then(x=>x.text())
    .then(x=>{
      divDestination.innerHTML=x;
        divDestination.querySelectorAll("script")
        .forEach(x=>{
          var sc=document.createElement("script");
          sc.appendChild(document.createTextNode(x.innerText));
          divDestination.appendChild(sc)
      })      
  })

根据Danny '365CSI' Engelman的评论,这里有一个通用的解决方案:

<script>
  alert("This script always runs.");
  script01 = true;
</script>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
 onload="if(typeof script01==='undefined') eval(this.previousElementSibling.innerHTML)">

使用它作为innerHTML(即由XMLHttpRequest加载)或直接(即由PHP后端插入),脚本总是加载一次。

解释:脚本加载innerHTML不执行,但onload内容属性是。如果脚本没有执行(作为innerHTML添加),那么脚本将在image onload事件中执行。如果脚本已加载(由后端添加),则定义script01变量,onload将不会第二次运行脚本。

下面是一个递归地将所有脚本替换为可执行脚本的方法:

function nodeScriptReplace(node) {
        if ( nodeScriptIs(node) === true ) {
                node.parentNode.replaceChild( nodeScriptClone(node) , node );
        }
        else {
                var i = -1, children = node.childNodes;
                while ( ++i < children.length ) {
                      nodeScriptReplace( children[i] );
                }
        }

        return node;
}
function nodeScriptClone(node){
        var script  = document.createElement("script");
        script.text = node.innerHTML;

        var i = -1, attrs = node.attributes, attr;
        while ( ++i < attrs.length ) {                                    
              script.setAttribute( (attr = attrs[i]).name, attr.value );
        }
        return script;
}

function nodeScriptIs(node) {
        return node.tagName === 'SCRIPT';
}

示例调用:

nodeScriptReplace(document.getElementsByTagName("body")[0]);