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

示例代码:

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


当前回答

你也可以像这样包装你的<脚本>,它将被执行:

<your target node>.innerHTML = '<iframe srcdoc="<script>alert(top.document.title);</script>"></iframe>';

请注意:srcdoc中的作用域指向iframe,因此您必须像上面的示例一样使用top来访问父文档。

其他回答

从innerHTML执行(Java Script)标签

将脚本元素替换为具有class="javascript"类属性的div,并以</div>关闭

不要改变你想要执行的内容(以前是在script标签,现在是在div标签)

在你的页面中添加一个样式…

<style type="text/css"> .javascript {display: none;} > < /风格

现在使用jquery运行eval (jquery js应该已经包含在内)

   $('.javascript').each(function() {
      eval($(this).text());

    });`

你可以在我的博客上探索更多。

我使用了这个代码,它工作得很好

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div

简单,没有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)
      })      
  })

我对这个问题的解决方案是设置一个突变观察者来检测<script></script>节点,然后用一个新的具有相同src的<script></script>节点替换它。例如:

let parentNode = /* node to observe */ void 0
let observer = new MutationObserver(mutations=>{
    mutations.map(mutation=>{
        Array.from(mutation.addedNodes).map(node=>{
            if ( node.parentNode == parentNode ) {
                let scripts = node.getElementsByTagName('script')
                Array.from(scripts).map(script=>{
                    let src = script.src
                    script = document.createElement('script')
                    script.src = src
                    return script
                })
            }
        })
    })
})
observer.observe(document.body, {childList: true, subtree: true});

对于任何仍然试图这样做的人来说,不,您不能使用innerHTML注入脚本,但可以使用Blob和URL.createObjectURL将字符串加载到脚本标记中。

我已经创建了一个例子,让你运行一个字符串作为脚本,并通过一个承诺获得脚本的“exports”:

function loadScript(scriptContent, moduleId) {
    // create the script tag
    var scriptElement = document.createElement('SCRIPT');

    // create a promise which will resolve to the script's 'exports'
    // (i.e., the value returned by the script)
    var promise = new Promise(function(resolve) {
        scriptElement.onload = function() {
            var exports = window["__loadScript_exports_" + moduleId];
            delete window["__loadScript_exports_" + moduleId];
            resolve(exports);
        }
    });

    // wrap the script contents to expose exports through a special property
    // the promise will access the exports this way
    var wrappedScriptContent =
        "(function() { window['__loadScript_exports_" + moduleId + "'] = " + 
        scriptContent + "})()";

    // create a blob from the wrapped script content
    var scriptBlob = new Blob([wrappedScriptContent], {type: 'text/javascript'});

    // set the id attribute
    scriptElement.id = "__loadScript_module_" + moduleId;

    // set the src attribute to the blob's object url 
    // (this is the part that makes it work)
    scriptElement.src = URL.createObjectURL(scriptBlob);

    // append the script element
    document.body.appendChild(scriptElement);

    // return the promise, which will resolve to the script's exports
    return promise;
}

...

function doTheThing() {
    // no evals
    loadScript('5 + 5').then(function(exports) {
         // should log 10
        console.log(exports)
    });
}

我从我的实际实现中简化了它,所以不能保证它没有任何错误。但是这个原理是可行的。

如果你不关心在脚本运行后得到什么值,那就更简单了;只要省略承诺和加载部分。您甚至不需要包装脚本或创建全局窗口。__load_script_exports_财产。