让 innerHTML 进来的 script 代码跑起来
今天来简单聊聊如何让 innerHTML 进来的 scrip 代码跑起来的问题。
前台请求一个接口,接口返回一些 HTML 标签拼接成的字符串,以供前端直接 innerHTML 生成 DOM 元素,这样的做法非常普遍。但是你是否遇到过,如果字符串中拼接的 HTML 标签中有 script 标签,那么该段脚本是无法执行的,这并不是 bug,而是 w3c 的文档规定的。
比如如下这段代码,innerHTML 插入的脚本(alert)并不会执行:
<div id="myDiv">
</div>
<script>
// 模拟接口返回数据
var strVar = "";
strVar += "<script>alert('hello world')<\/script>";
document.getElementById('myDiv').innerHTML = strVar;
</script>
那么问题来了,如何使得 innerHTML 进来的 script 代码能够跑起来?
方案一:重新构造 script 标签
思路非常简单,构造新的 script 标签,然后该标签的 innerHTML 赋值为需要渲染的脚本。伪代码如下:
var s = document.createElement('script');
s.innerHTML = text;
document.body.appendChild(s);
当然如果要写的完美一点,执行完 s 后还需要 remove 掉。如何获取 text 值?两个方法,其一可以正则匹配 strVal,提取 script 标签内的内容,这点和 BigRender 类似,而 BigRender 除了提取 script 标签,还需要提取 style 标签,无疑更复杂;第二个方法是可以用 document.getElementsByTagName('script') 获取插入 DOM 但并未执行的 script 脚本,但是这样会把页面所有脚本全部提取,所以还需要判断。(可以获取某一节点下的 script 标签)
如果是外部的 js 文件,需要为新建的 script 元素添加 src 属性即可。
方案二:eval 大法
事实上,如果是 inline JavaScript,方案一求得的 text,可以直接 eval 之。
但是如果是外联 js 文件,同上,需要新建 script 标签然后指定 src 属性。
方案三:document.write
document.write 接收一个字符串作为参数,并且支持 script 标签以及其他 HTML 标签拼成的字符串,看起来似乎是完美的方案。不过鉴于 document.write 的怪属性,只适合 strVal 在首页输出流中的渲染情况,如果是异步的请求,就可以放弃了。
举个栗子:
hello world
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<div>
<script>
$.get('data.php', function(data) {
document.write(data);
})
</script>
</div>
目的似乎是为了在 div 中嵌入 data,但是 hello world 字样也消失了,很显然,异步请求后重启输入流,将页面全部覆盖掉了。
方案四:jQuery html() 方法
使用封装过的方法无疑是个好办法:
<div id="myDiv"></div>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$.get('data.php', function(data) {
$('#myDiv').html(data);
})
</script>
如果已经引入了 jQuery,无疑是最佳方案,没必要重复造轮子了。
方案五: 利用 img 标签
黑魔法,如果后台接口可控的话。
比方说我希望 innerHTML 的内容如下:
<div></div>
<script>
alert('hello world');
</script>
我们可以这样构造 img:
<div id='myDiv'></div>
<script>
var str = "<div></div>";
str += "<img src='empty.gif' onload='alert(\"hello world\"); this.parentNode.removeChild(this);' />";
document.getElementById('myDiv').innerHTML = str;
</script>
其他: 特殊的 IE
事实上,一定条件下,innerHTML 进来的 script 脚本,在 IE(IE9-?)下是可以触发的。
需要满足的条件如下:
- 脚本有 defer 属性
- 脚本并不是 innerHTML 的第一个元素( script 元素必须位于 "有作用域的元素" 之后。如果通过innerHTML 插入的字符串开头就是一个 "无作用域的元素",那么 IE 会在解析这个字符串前先删除该元素)
code:
<body>
<div id='myDiv'></div>
<script type="text/javascript">
var strVar = "";
strVar += "<span style='display: none'>hack ie</span><script defer='true'>";
strVar += "alert('hello world');";
strVar += "<\/script>";
document.getElementById("myDiv").innerHTML = strVar;
</script>
</body>
参考:
- Have Your DOM and Script It Too
- Can scripts be inserted with innerHTML?
- http://w3help.org/zh-cn/causes/BX9029
- https://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
- https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
让 innerHTML 进来的 script 代码跑起来的更多相关文章
- 执行 innerHTML 里的 <script>
原文:执行 innerHTML 里的 <script> 背景 有时候我们会有把一整段 HTML 动态塞进页面的需求,例如渲染了一个模板,从服务器端获取了一段广告代码等.一般情况下我们使用 ...
- 出现“不能执行已释放的Script代码”错误的原因及解决办法
很多web开发者或许都遇到过这样的问题,程序莫名奇怪出现“不能执行已释放Script的代码”,错误行1,列1.对于这种消息描述不着边,行列描述更是让人迷茫的js错误,相信是所有调试js程序的朋友们最郁 ...
- 使用innerHTML生成的script节点不会发出请求与执行text属性
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Script 代码段
script代码段 1.script代码段的执行 在Javascript代码中,可以使用script作为基本标识,script代码段在运行过程中是分段解析与执行的. 2.script代码段执行流程 在 ...
- IE10弹窗showModalDialog关闭之后提示SCRIPT5011:不能执行已释放的Script代码
在Web开发中,经常使用showModalDialog弹窗 今天遇到一个小问题,IE10中弹窗关闭之后提示SCRIPT5011:不能执行已释放的Script代码 网上搜罗了一些资料,发现大多都提到对象 ...
- 有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果
问题:有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果 解决: 页面代码是至上而下执行的,如果你的这个标签在< ...
- link标签和script标签跑到body下面,网页顶部有空白
用UltraEdit的16进制编辑模式查看代码,都是EF BB BF开头的,说明都是带BOM的.我手动的将所有文件转成UTF-8 without BOM.页面终于正常了.link,script标签乖乖 ...
- innerHTML动态添加html代码和脚本兼容性问题处理方法
给某个元素的innerHTML赋值,并使得值中的js代码有效(兼容多个浏览器) 症状:给某个元素的 innerHTML 设置值时,如果提供的 HTML 代码中包含js脚本,很多时候这些脚本无效,或者在 ...
- 在纯HTML的静态网页中添加一段统计网页访问量的JAVA Script代码?
如何在网站上进行流量统计呢,可以找第三方服务网站去注册,但也可以在网站上直接添加代码,只需将以下代码copy到你的网页中,复制到</body>之前就可以啦!是不是很简单啊! <scr ...
随机推荐
- 简述MVC框架模式以及在你(Android)项目中的应用
标题是阿里电话面试的问题,一直以为自己很清楚MVC模式,结果被问到时,居然没法将MVC和Android中各个组件对应起来,所以,面试肯定挂了,不过面试也是学习的一种方式,可以知道大公司看中什么,以及自 ...
- Spring Batch 批处理框架
<Spring Batch 批处理框架>基本信息作者: 刘相 出版社:电子工业出版社ISBN:9787121252419上架时间:2015-1-24出版日期:2015 年2月开本:16开页 ...
- Tomcat:bio nio 的设计
BIO 由Acceptor接收Socket,将其转交给Worker来处理. NIO 由Acceptor接收Socket,将其转交给Poller来轮询处理.Poller再将可处理的Socket交给Wo ...
- java统计汉字
public class TotalUtil { public static int getSum(String text) { String reg = "^[\u4e00- ...
- 编写IoDemo.java的Java应用程序,程序完成的功能是:首先读取text.txt文件内容,再通过键盘输入文件的名称为iodemo.txt,把text.txt的内容存入iodemo.txt
package zuoye; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExcep ...
- storm实战:基于storm,kafka,mysql的实时统计系统
公司对客户开放多个系统,运营人员想要了解客户使用各个系统的情况,在此之前,数据平台团队已经建设好了统一的Kafka消息通道. 为了保证架构能够满足业务可能的扩张后的性能要求,选用storm来处理各个应 ...
- DateTime , DateTime2 ,DateTimeOffset 之间的小区别
闲来无事列了个表比对一下这3兄弟之间还是有一点差距的╮(╯_╰)╭ DateTime DateTime2 DateTimeOffset 日期范围 1753-01-01到 9999-12-31 00 ...
- 【mysql】关于乐观锁
一.乐观锁介绍 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检,乐观锁适用于 ...
- docker-6 管理工具
Shipyard 是一个基于 Web 的 Docker 管理工具,支持多 host,可以把多个 Docker host 上的 containers 统一管理:可以查看 images,甚至 build ...
- 《InsideUE4》-3-GamePlay架构(二)Level和World
UE4深入学习QQ群: 456247757 引言 上文谈到Actor和Component的关系,UE利用Actor的概念组成一片游戏对象森林,并利用Component组装扩展Actor的能力,让世界里 ...