今天来简单聊聊如何让 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>

参考:

让 innerHTML 进来的 script 代码跑起来的更多相关文章

  1. 执行 innerHTML 里的 <script>

    原文:执行 innerHTML 里的 <script> 背景 有时候我们会有把一整段 HTML 动态塞进页面的需求,例如渲染了一个模板,从服务器端获取了一段广告代码等.一般情况下我们使用 ...

  2. 出现“不能执行已释放的Script代码”错误的原因及解决办法

    很多web开发者或许都遇到过这样的问题,程序莫名奇怪出现“不能执行已释放Script的代码”,错误行1,列1.对于这种消息描述不着边,行列描述更是让人迷茫的js错误,相信是所有调试js程序的朋友们最郁 ...

  3. 使用innerHTML生成的script节点不会发出请求与执行text属性

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  4. Script 代码段

    script代码段 1.script代码段的执行 在Javascript代码中,可以使用script作为基本标识,script代码段在运行过程中是分段解析与执行的. 2.script代码段执行流程 在 ...

  5. IE10弹窗showModalDialog关闭之后提示SCRIPT5011:不能执行已释放的Script代码

    在Web开发中,经常使用showModalDialog弹窗 今天遇到一个小问题,IE10中弹窗关闭之后提示SCRIPT5011:不能执行已释放的Script代码 网上搜罗了一些资料,发现大多都提到对象 ...

  6. 有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果

    问题:有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果 解决: 页面代码是至上而下执行的,如果你的这个标签在< ...

  7. link标签和script标签跑到body下面,网页顶部有空白

    用UltraEdit的16进制编辑模式查看代码,都是EF BB BF开头的,说明都是带BOM的.我手动的将所有文件转成UTF-8 without BOM.页面终于正常了.link,script标签乖乖 ...

  8. innerHTML动态添加html代码和脚本兼容性问题处理方法

    给某个元素的innerHTML赋值,并使得值中的js代码有效(兼容多个浏览器) 症状:给某个元素的 innerHTML 设置值时,如果提供的 HTML 代码中包含js脚本,很多时候这些脚本无效,或者在 ...

  9. 在纯HTML的静态网页中添加一段统计网页访问量的JAVA Script代码?

    如何在网站上进行流量统计呢,可以找第三方服务网站去注册,但也可以在网站上直接添加代码,只需将以下代码copy到你的网页中,复制到</body>之前就可以啦!是不是很简单啊! <scr ...

随机推荐

  1. Serena Dimensions 介绍

    Serena Dimensions是配置管理工具,基于进程的软件更改和配置管理解决方案. 官方网址:http://www.serena.com/index.php/en/products/applic ...

  2. SQL Server 2014新特性——事务持久性控制

    控制事务持久性 SQL Server 2014之后事务分为2种:完全持久, 默认或延迟的持久. 完全持久,当事务被提交之后,会把事务日志写入到磁盘,完成后返回给客户端. 延迟持久,事务提交是异步的,在 ...

  3. 【hadoop】——HDFS解压缩实现

    转载请注明出处:http://www.cnblogs.com/zhengrunjian/p/4527220.html 所有源码在github上,https://github.com/lastsweet ...

  4. 使用SQL检测死锁

    第一步:首先创建两个测试表,表goods_sort和goods 表goods_sort:创建并写入测试数据 IF EXISTS(SELECT name FROM sysobjects WHERE na ...

  5. oracle函数--trunc

    作用:截取 语法:trunc(date,[fmt])   TRUNC函数,ORA-01898 精度说明符过多 TRUNC(SYSDATE)即可默认当前日期(年月日),---写到这一步就好了 TRUNC ...

  6. 使用elasticsearch的关键技术点

    前言 最近有一个项目用到了搜索引擎,这里记录下使用过程中遇到的一些问题和解决方案. 0.准备工作 1)安装elasticsearch 2)安装Marvel 3)安装head tips:在es的配置文件 ...

  7. .Net程序员之Python基础教程学习----字符串的使用 [Second Day]

         在The FirstDay 里面学习了列表的元组的使用,今天开始学习字符串的使用.字符串的使用主要要掌握,字符串的格式化(C语言中我们应该都知道,Python和C语言差别不大),字符串的基本 ...

  8. AC日记——整理药名 openjudge 1.7 15

    15:整理药名 总时间限制:  1000ms 内存限制:  65536kB 描述 医生在书写药品名的时候经常不注意大小写,格式比较混乱.现要求你写一个程序将医生书写混乱的药品名整理成统一规范的格式,即 ...

  9. 正弦 sin 余弦 cos

    正弦 以下概念需掌握 直角,锐角 sinA = 对边 / 斜边 性質 奇偶性 奇 定義域 (-∞,∞) 到達域 [-1,1] 周期 2π 在數學中,正弦是一種週期函數,是三角函数的一種.它的定义域是整 ...

  10. 入门训练 Fibonacci数列

      入门训练 Fibonacci数列   时间限制:1.0s   内存限制:256.0MB 问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时, ...