让 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 ...
随机推荐
- 中控考勤仪IFace302多线程操作时无法订阅事件
场景: 在各办事点安装中控考勤仪Iface302,各办事点的工作人员上下班报到时使用指纹或面纹进行自动登记,验证成功后将与服务吕进行通讯记录相关的考勤信息. 条件限制: 由于Iface302设备不支持 ...
- Java并发之ThreadPoolExecutor 线程执行服务
package com.thread.test.thread; import java.util.concurrent.ExecutorService; import java.util.concur ...
- coursera机器学习-logistic回归,正则化
#对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...
- Java设计模式学习笔记(观察者模式)
观察者模式说起来很简单,就是一个订报纸的模式.但是实际上这部分我觉得还是很有意思的,<Head First设计模式>里还有一些还没看完,也是因为理解的不够深吧. 观察者模式会包含两个组件: ...
- 神奇的expect
想写自动化脚本的时候,遇到需要交互的,如ssh,scp,就束手无策,直到我知道了expect. expect 有一系列expect-send对组成,就像聊天一样. expect A send B ex ...
- SQLITE配置环境变量
SQLITE配置环境变量和Java的配置其实是一样的,不过好像每个人配的时候不完全相同, 有的机器可以,另外一些机器同样的方法却行不通,总之思路是一样的多试几种,总有合适的参数 下面是我在配置时截 ...
- [转]在ASP.NET开发中容易忽略的2个小问题 Cookie乱码存取异常 和 iframe弹框的login跳转
本文转自:http://www.cnblogs.com/outtamyhead/p/3642729.html 本文地址:http://www.cnblogs.com/outtamyhead/p/364 ...
- Python Select 解析
首先列一下,sellect.poll.epoll三者的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select ...
- POJ1523 SPF[无向图割点]
SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8139 Accepted: 3723 Description C ...
- jmeter 与 java http
jmeter 如果对java代码进行测试 1.eclips中创建一个项目,且写一个待测试的简单java代码 2.将jmeter路径下 x:\xx\lxx\Dowxxxxxx\apache-jmeter ...