脚本可以用innerHTML插入吗?

我试图在<div>上使用innerHTML将一些脚本加载到页面中。 看来,脚本加载到DOM,但它永远不会执行(至less在Firefox和Chrome)。 有没有办法让脚本执行时,用innerHTML插入它们?

示例代码:

 <!DOCTYPE html> <html> <body onload="document.getElementById('loader').innerHTML = '<script>alert(\'hi\')<\/script>'"> Shouldn't an alert saying 'hi' appear? <div id="loader"></div> </body> </html> 

您必须使用eval()来执行您已经作为DOM文本插入的任何脚本代码。

MooTools会自动为你做这件事,我相信jQuery也会这样(取决于版本,jQuery版本1.6+使用eval )。 这样可以节省很多parsing<script>标签和转义内容的麻烦,以及其他一些“陷阱”。

一般情况下,如果你自己要eval() ,你希望创build/发送脚本代码,而不需要任何HTML标记,比如<script> ,因为这些代码不会正确地eval()

这是一个非常有趣的解决scheme,您的问题: http : //24ways.org/2005/have-your-dom-and-script-it-too

所以用这个代替脚本标签:

<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />

下面是一个recursion地用可执行文件replace所有脚本的方法:

 function nodeScriptReplace(node) { if ( nodeScriptIs(node) === true ) { node.parentNode.replaceChild( nodeScriptClone(node) , node ); } else { var i = 0; var children = node.childNodes; while ( i < children.length ) { nodeScriptReplace( children[i++] ); } } return node; } function nodeScriptIs(node) { return node.tagName === 'SCRIPT'; } function nodeScriptClone(node){ var script = document.createElement("script"); script.text = node.innerHTML; for( var i = node.attributes.length-1; i >= 0; i-- ) { script.setAttribute( node.attributes[i].name, node.attributes[i].value ); } return script; } 

示例调用:

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

您可以创build脚本,然后注入内容。

 var g = document.createElement('script'); var s = document.getElementsByTagName('script')[0]; g.text = "alert(\"hi\");" s.parentNode.insertBefore(g, s); 

这适用于所有浏览器:)

我用这个代码,它工作正常

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

对于任何仍在尝试这样做的人,不,不能使用innerHTML注入脚本,但可以使用BlobURL.createObjectURL将string加载到脚本标记中。

我创build了一个例子,可以让你将一个string作为脚本运行,并获得通过承诺返回的脚本的“输出”:

 function loadScript(scriptContent, moduleId) { // create the script tag var scriptElement = document.createElement('SCRIPT'); // create a promise which will resolve to the script's 'exports' // (ie, 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) }); } 

我已经简化了这个从我的实际实现,所以没有承诺,没有任何错误。 但是这个原理起作用。

如果你不关心在脚本运行之后获得任何价值,那更容易; 只是放弃Promiseonload位。 您甚至不需要包装脚本或创build全局window.__load_script_exports_属性。

克拉西米尔Tsonev有一个伟大的解决scheme,克服所有问题。 他的方法不需要使用eval,所以不存在性能和安全问题。 它允许你设置innerHTMLstring包含html与js,并立即将其转换为DOM元素,同时还执行沿代码存在的js部分。 简短,简单,并按照你的想法工作。

享受他的解决scheme

http://krasimirtsonev.com/blog/article/Convert-HTML-string-to-DOM-element

重要笔记:

  1. 你需要用div标签包装目标元素
  2. 你需要用div标签包装srcstring。
  3. 如果直接编写srcstring,并且包含js部分,请注意正确编写closures脚本标记(使用\ before /),因为这是一个string。

使用$(parent).html(code)而不是parent.innerHTML = code

下面还修复了使用document.write和通过src属性加载的脚本的脚本。 不幸的是,即使这不适用于Google 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 }) } 

资源

是的,你可以,但是你必须在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; } 

下面是一个recursion函数,用于设置我在广告服务器中使用的元素的innerHTML:

 // o: container to set the innerHTML // html: html text to set. // clear: if true, the container is cleared first (children removed) function setHTML(o, html, clear) { if (clear) o.innerHTML = ""; // Generate a parseable object with the html: var dv = document.createElement("div"); dv.innerHTML = html; // Handle edge case where innerHTML contains no tags, just text: if (dv.children.length===0){ o.innerHTML = html; return; } for (var i = 0; i < dv.children.length; i++) { var c = dv.children[i]; // n: new node with the same type as c var n = document.createElement(c.nodeName); // copy all attributes from c to n for (var j = 0; j < c.attributes.length; j++) n.setAttribute(c.attributes[j].nodeName, c.attributes[j].nodeValue); // If current node is a leaf, just copy the appropriate property (text or innerHTML) if (c.children.length == 0) { switch (c.nodeName) { case "SCRIPT": if (c.text) n.text = c.text; break; default: if (c.innerHTML) n.innerHTML = c.innerHTML; break; } } // If current node has sub nodes, call itself recursively: else setHTML(n, c.innerHTML, false); o.appendChild(n); } } 

你可以在这里看到演示。

从innerHTML执行(Java Script)标记

把你的脚本元素replace为具有类属性class =“javascript”的</div>然后用</div>closures它

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

在你的网页中添加一种风格…

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

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

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

您可以在我的博客上浏览更多。

我解决这个问题的方法是设置一个Mutation Observer来检测<script></script>节点,然后用一个新的<script></script>节点replace它。 例如:

 let parentNode = /* your node */ 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中后,将标签附加到头部,然后运行

我试过这个,它的工作。 谢谢@ mwilcox。

 var maint = document.getElementById("maint"); maint.innerHTML = ''; var inner = '<form >'+ 'add new member:-<br>'+ '<input type="text" name="namea" placeholder="enter ur name">'+ '</form >'; maint.innerHTML = inner;