我尝试在<div>上使用innerHTML加载一些脚本到页面中。脚本似乎加载到DOM中,但它从未执行(至少在Firefox和Chrome中)。有一种方法让脚本执行时插入他们与innerHTML?
示例代码:
<!DOCTYPE html >
< html >
<身体onload = " . getelementbyid(机)。innerHTML = '<script>alert(\'hi\')<\/script>'">
难道不应该出现“hi”的提醒吗?
< div id = "装载机" > < / div >
身体< / >
< / html >
我有这个问题与innerHTML,我不得不追加一个Hotjar脚本的“头部”标签我的Reactjs应用程序,它将必须立即执行追加后。
将动态节点导入“head”标签的一个很好的解决方案是React-helment模块。
此外,对于所提出的问题,还有一个有用的解决方案:
在innerHTML中没有脚本标记!
事实证明,HTML5不允许使用innerHTML属性动态添加脚本标记。因此,下面的代码将不会执行,也不会出现Hello World!
element.innerHTML = "<script>alert('Hello World!')</script>";
这在HTML5规范中有记录:
注意:使用innerHTML插入的脚本元素不执行时
它们是插入的。
但是要注意,这并不意味着innerHTML不受跨站点脚本的影响。可以通过innerHTML执行JavaScript,而不使用MDN的innerHTML页面上所示的标记。
解决方案:动态添加脚本
要动态添加脚本标记,您需要创建一个新的脚本元素并将其附加到目标元素。
你可以为外部脚本这样做:
var newScript = document.createElement("script");
newScript.src = "http://www.example.com/my-script.js";
target.appendChild(newScript);
和内联脚本:
var newScript = document.createElement("script");
var inlineScript = document.createTextNode("alert('Hello World!');");
newScript.appendChild(inlineScript);
target.appendChild(newScript);
这里的解决方案不使用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;
}
是的,你可以,但你必须在DOM之外做,而且顺序必须是正确的。
var scr = '<scr'+'ipt>alert("foo")</scr'+'ipt>';
window.onload = function(){
var n = document.createElement("div");
n.innerHTML = scr;
document.body.appendChild(n);
}
...将提醒'foo'。这行不通:
document.getElementById("myDiv").innerHTML = scr;
即使这样也不行,因为先插入节点:
var scr = '<scr'+'ipt>alert("foo")</scr'+'ipt>';
window.onload = function(){
var n = document.createElement("div");
document.body.appendChild(n);
n.innerHTML = scr;
}
根据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将不会第二次运行脚本。