Cra*_*aig 194 html javascript dom innerhtml
我尝试使用innerHTMLa 将一些脚本加载到页面中<div>.看起来脚本加载到DOM中,但它永远不会被执行(至少在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>Run Code Online (Sandbox Code Playgroud)
小智 80
这是一个非常有趣的解决方案:http: //24ways.org/2005/have-your-dom-and-script-it-too
因此,请使用此代替脚本标记:
<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />
zom*_*bat 78
您必须使用eval()来执行您作为DOM文本插入的任何脚本代码.
MooTools会自动为您完成此操作,我确信jQuery也会这样(取决于版本.jQuery版本1.6+使用eval).这节省了解析<script>标签和转义内容的麻烦,以及一堆其他"陷阱".
通常,如果你eval()自己去做,你想创建/发送脚本代码而不使用任何HTML标记<script>,因为这些标记不eval()正确.
mom*_*omo 70
这是一个递归替换所有可执行脚本的方法:
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;
}
Run Code Online (Sandbox Code Playgroud)
示例电话:
nodeScriptReplace(document.getElementsByTagName("body")[0]);
Run Code Online (Sandbox Code Playgroud)
Pab*_*tti 39
您可以创建脚本然后注入内容.
var g = document.createElement('script');
var s = document.getElementsByTagName('script')[0];
g.text = "alert(\"hi\");"
s.parentNode.insertBefore(g, s);
Run Code Online (Sandbox Code Playgroud)
这适用于所有浏览器:)
Fir*_*zam 25
我用过这段代码,工作正常
var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
eval(arr[n].innerHTML)//run script inside div
Run Code Online (Sandbox Code Playgroud)
p.d*_*iel 14
我在使用innerHTML 时遇到了这个问题,我不得不将一个Hotjar 脚本附加到我的Reactjs 应用程序的“head”标签中,并且它必须在附加后立即执行。
将 Node 动态导入“head”标签的一个很好的解决方案是React-helment模块。
此外,对于所提出的问题,还有一个有用的解决方案:
innerHTML 中没有脚本标签!
事实证明,HTML5 不允许使用 innerHTML 属性动态添加脚本标签。所以下面的将不会执行,也不会有警告说 Hello World!
element.innerHTML = "<script>alert('Hello World!')</script>";
Run Code Online (Sandbox Code Playgroud)
这记录在 HTML5 规范中:
注意:使用innerHTML 插入的脚本元素在插入时不会执行。
但请注意,这并不意味着 innerHTML 不受跨站点脚本的影响。如MDN 的 innerHTML 页面所示,可以通过 innerHTML 执行 JavaScript,而无需使用标签。
解决方案:动态添加脚本
要动态添加脚本标记,您需要创建一个新的脚本元素并将其附加到目标元素。
您可以对外部脚本执行此操作:
var newScript = document.createElement("script");
newScript.src = "http://www.example.com/my-script.js";
target.appendChild(newScript);
Run Code Online (Sandbox Code Playgroud)
和内联脚本:
var newScript = document.createElement("script");
var inlineScript = document.createTextNode("alert('Hello World!');");
newScript.appendChild(inlineScript);
target.appendChild(newScript);
Run Code Online (Sandbox Code Playgroud)
Til*_*ddy 13
每次我想动态插入脚本标签时,我都会这样做!
const html =
`<script>
alert(' there ! Wanna grab a ');
</script>`;
const scriptEl = document.createRange().createContextualFragment(html);
parent.append(scriptEl);
Run Code Online (Sandbox Code Playgroud)
注意:使用 ES6
编辑 1:为你们澄清 - 我已经看到很多答案的使用,appendChild并想让你们知道它的工作原理完全一样append
Joh*_*ald 12
这是mmm 很棒的解决方案的更现代(更简洁)的版本:
function executeScriptElements(containerElement) {
const scriptElements = containerElement.querySelectorAll("script");
Array.from(scriptElements).forEach((scriptElement) => {
const clonedElement = document.createElement("script");
Array.from(scriptElement.attributes).forEach((attribute) => {
clonedElement.setAttribute(attribute.name, attribute.value);
});
clonedElement.text = scriptElement.text;
scriptElement.parentNode.replaceChild(clonedElement, scriptElement);
});
}
Run Code Online (Sandbox Code Playgroud)
注意:我还尝试过使用cloneNode()或outerHTML的替代解决方案,但这不起作用。
你可以这样做:
var mydiv = document.getElementById("mydiv");
var content = "<script>alert(\"hi\");<\/script>";
mydiv.innerHTML = content;
var scripts = mydiv.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
eval(scripts[i].innerText);
}
Run Code Online (Sandbox Code Playgroud)
对于仍在尝试执行此操作的任何人,不,您不能使用 注入脚本innerHTML,但可以使用Blob和将字符串加载到脚本标记中URL.createObjectURL。
我创建了一个示例,它允许您将字符串作为脚本运行,并获取通过承诺返回的脚本的“导出”:
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)
});
}
Run Code Online (Sandbox Code Playgroud)
我已经从我的实际实现中简化了这一点,所以不保证其中没有任何错误。但是这个原理是有效的。
如果你不关心在脚本运行后获得任何价值,那就更容易了;只需省略Promise和onload位。您甚至不需要包装脚本或创建全局window.__load_script_exports_属性。
这是一个递归函数,用于设置我在广告服务器中使用的元素的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在此处查看演示。
这里一个解决方案,不使用eval,并与作品的脚本,链接脚本,以及与模块。
该函数接受 3 个参数:
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;
}
Run Code Online (Sandbox Code Playgroud)