让 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 ...
随机推荐
- pentaho cde数据联动,下拉框,文本框,图形
先看一下效果: 开源bi工具pentaho数据联动,和传统意义上的更改数据不同,pentaho cde 需要一个监听来动态传值. 说一下需要注意的几个地方吧 1.参数是不能在两个图表中直接传递的,必须 ...
- MongoDB ServerStatus返回信息
ServerStatus返回信息 ServerStatus返回mongodb中很多信息 http://docs.mongodb.org/manual/reference/command/serverS ...
- 表单和iframe的使用
图片热点: 规划出图片上的一个区域,可以做出超链接,直接点击图片区域就可以完成跳转的效果.示例: 网页划区: 在一个网页里,规划出一个区域用来展示另一个网页的内容.示例: 网页的拼接: 在一个网络页面 ...
- coursera机器学习笔记-机器学习概论,梯度下降法
#对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...
- 烂泥:Linux源码包制作RPM包之Apache
本文由秀依林枫提供友情赞助,首发于烂泥行天下 公司服务器比较多,需要把apache源码包制作成rpm包,然后放到公司内网yum源上进行下载安装.apache的rpm包安装方式比源码安装方式比较快,这能 ...
- WIN 下的超动态菜单(一)
WIN 下的超动态菜单(一)介绍 WIN 下的超动态菜单(二)用法 WIN 下的超动态菜单(三)代码 作者:黄山松,发表于博客园:http://www.cnblogs.com/tomview/ ...
- linux 添加用户、权限
# useradd –d /usr/sam -m sam 此命令创建了一个用户sam,其中-d和-m选项用来为登录名sam产生一个主目录/usr/sam(/usr为默认的用户主目录所在的父目录). 假 ...
- 2-Fedora 17系统安装准备
在安装Fedora 17系统之前应做好准备工作,这些准备工作包括了解安装系统的硬件要求,Linux系统磁盘分区方案和挂载目录以及制作安装引导盘 学习重点: 硬件要求 硬件兼容性 分区方案 学习内容: ...
- Hyper-V架构与VMware ESXi的差异
微软的Hyper-V与VMware的ESXi在架构上有众多不同,然而很多虚拟化管理员并未意识到这些差异.而且很多管理员同样对Hyper-V是在主机操作系统上运行感到困惑. 有关微软Hyper-V的一个 ...
- go语言之并发
简介 多核处理器越来越普及,那有没有一种简单的办法,能够让我们写的软件释放多核的威力?答案是:Yes.随着Golang, Erlang, Scale等为并发设计的程序语言的兴起,新 ...