页面动态加入 script 标签并执行其代码
在页面中动态追加HTML片段的时候,有时候动态添加的代码会含有script标签,比如用了一些模板引擎,或者你的代码有些复杂的时候。然而我们用DOM提供的innerHTML方式来添加代码的时候,script标签中的代码并不能执行,如果有src属性,指向的外联文件也不会被加载,这并不是浏览器的bug,因为W3C文档就是这么规定的。
那我们有什么办法可以恢复追加的script标签的代码执行能力呢?
重新构造script标签 这个思路其实非常简单,用innerHTML添加的script无法执行,但是我们script创建节点,并用appendChild追加上去是可以的,所以我们只需要做一下二次工作就可以了,看下面的例子:
页面上有个容器:
JS代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var html = '<div>html</div><script>alert(1);<\/script>' ;var cnt = document .getElementById('cnt' );cnt.innerHTML = html; var oldScript = cnt.getElementsByTagName('script' )[0 ];if (oldScript) { var newScript = document .createElement('script' ); newScript.type = 'text/javascript' ; newScript.src = oldScript.src; elem.replaceChild(script, oldScript); }
这只是内联script的方法,如果是引用的外部js文件,那么我们需要为新创建的script节点指定src属性。
eval大法 虽然eval因为其安全性不推荐使用,但是在此特殊场景,使用eval确是非常简单的解决方案,就是把script标签中的代码eval一下手动执行,就ok了,看下面代码:
1 2 3 4 5 6 7 8 9 10 var html = '<div>html</div><script>alert(1);<\/script>' ;var cnt = document .getElementById('cnt' );cnt.innerHTML = html; var oldScript = cnt.getElementsByTagName('script' )[0 ];if (oldScript) { cnt.removeChild(oldScript); var scriptText = oldScript.text; eval (scriptText); }
对于内联的代码,简单而有效,如果是外部js文件,那么还是使用上面的方法,为新创建的script节点指定src属性。
document.write大法 此方法可以在页面上直接输出任何html内容,包含script标签的话会立即执行,所以也是一种方案,如下:
1 2 var html = '<div>html</div><script>alert(1);<\/script>' ;document .write(html);
代码就直接执行了。但是他的缺点是如果代码写在文档底部,输出的内容会把页面上的其他内容全部覆盖,相当于清空了页面。解决的办法只有这样了:
1 <div id ="cont" > <script type ="text/javascript" > document .write(html);</script > </div >
直接把它放在标签中,就会往这个标签中输出东西了。
使用jQuery 上面的方法说来说去,都不如jQuery简单,因为jQuery的html(),append()等方法内部已经做了处理,如果参数中含有script标签,内部会使用eval和创建新节点的方式进行处理,如果是外联的js文件,jQuery会发一个同步的ajax请求来获取代码,注意,是同步的!所以不论是内联的js代码还是外联的js文件,都可以正常执行,同时在执行完后删去script标签。所以,使用jQuery你只需要这样:
1 2 3 var html = '<div>html</div><script>alert(1);<\/script>' ;$('#cnt' ).html(html);
这个alert就妥妥的执行了。
本文参考自吕大豹(Double.Lv) ,感谢作者的无私分享!