IE 和 Firefox 可以通过特定方法使 innerHTML 方法载入的 SCRIPT 标...
2013-10-17 00:00
190 查看
IE 和 Firefox 可以通过特定方法使 innerHTML 方法载入的 SCRIPT 标签中的 JavaScript 代码在页面加载后也可以执行
标准参考
根据 W3C HTML4.01 规范中的描述,SCRIPT 标签内的 "脚本" 只会在页面加载时执行一次,或者通过绑定事件实现在页面加载后脚本能够重复地执行。defer 属性是 SCRIPT 元素的特有属性,这是一个布尔型属性,它通知用户端这段脚本中不会生产文档内容(如 "documnet.write" ),所以不必现在立即执行,一般的拥有 defer 属性的 SCRIPT 元素中的脚本会较晚的被执行。
关于 SCRIPT 元素的详细资料,请参考 HTML4.01 规范 18 中的内容。
关于 defer 属性的详细资料,请参考 HTML4.01 规范 18.2.1 中的内容。
问题描述
在 IE6 IE7 IE8 中,当使用 innerHTML 方法插入脚本时,SCRIPT 元素必须设置 defer 属性。在 Firefox 中,先将被插入 HTML 代码的元素从其父元素中移除,然后使用 innerHTML 插入包含 SCRIPT 元素的代码,最后将这个元素恢复至原父元素中,则经过此操作后 SCRIPT 中的脚本可以被执行。
造成的影响
若利用某些浏览器的特性迫使通过 innerHTML 方法载入的 SCRIPT 标签内的脚本执行已达到某些目的,则在 IE、Firefox 之外的浏览器中脚本将不被执行,从而造成各种兼容性问题。受影响的浏览器
IE6 IE7 IE8 | 使用 innerHTML 方法插入脚本时,SCRIPT 元素必须设置 defer 属性。 |
---|---|
Firefox | 先将被插入 HTML 代码的元素从其父元素中移除,然后使用innerHTML插入包含SCRIPT元素的代码,最后将这个元素恢复至原父元素中,则经过此操作后SCRIPT中的脚本可以被执行。 |
问题分析
所有浏览器中,默认情况下通过 innerHTML 方法动态插入到页面中的 SCRIPT 标签中的脚本代码均不能被执行。分析以下代码:
<html> <head> </head> <body> <div id="d">Some text</div> <script> var a = "<div>a DIV</div><script>alert('alert');<\/script>"; document.getElementById("d").innerHTML = a; </script> </body> </html>
上面代码中 DIV 元素【d】的初始内容为 "Some text" ,随后通过 innerHTML 方法将【d】中内容替换为一个 DIV 元素及一个 SCRIPT 元素,SCRIPT 元素内包含一段 JavaScript 脚本。
这段代码在所有浏览器中均没有执行 SCRIPT 元素中的脚本。
这是因为根据 W3C 规范,SCRIPT 标签中所指的脚本仅在浏览器第一次加载页面时对其进行解析并执行其中的脚本代码,所以通过 innerHTML 方法动态插入到页面中的 SCRIPT 标签中的脚本代码在所有浏览器中默认情况下均不能被执行。
下面分析 IE 中使 innerHTML 插入 HTML 代码的脚本执行的特殊方法及其 Bug:
MSDN 中关于 innerHTML 方法中提到:
当使用 innerHTML 方法插入脚本时,SCRIPT 元素必须设置 defer 属性。
defer1.html |
---|
<html> <head> </head> <body> <script defer> alert("with defer, run later."); document.write("with defer, run later."); </script> <script> alert("without defer, run immediately."); document.write("without defer, run immediately."); </script> </body> </html> |
defer2.html |
<html> <head> </head> <body> <script defer src="defer.js"></script> <script src="normal.js"></script> </body> </html> |
defer.js alert("with defer, run later."); document.write("with defer, run later."); |
normal.js alert("without defer, run immediately."); document.write("without defer, run immediately."); |
IE | Firefox | Chrome, Safari, Opera | |
---|---|---|---|
defer1.html | alert顺序:without defer, run immediately. ->with defer, run later. 页面输出:with defer, run later. | alert顺序:with defer, run later. -> without defer, run immediately. 页面输出:with defer, run later. without defer, run immediately. | |
defer2.html | alert顺序:without defer, run immediately. ->with defer, run later. 页面输出:with defer, run later. | alert顺序:without defer, run immediately. ->with defer, run later. 页面输出:without defer, run immediately. | alert顺序:with defer, run later. ->without defer, run immediately. 页面输出:with defer, run later. without defer, run immediately. |
IE 对于 SCRIPT 元素内的脚本即由 SCRIPT 元素引入的脚本文件均具备延迟运行的效果。
Firefox 仅对通过 SCRIPT 元素引入的脚本文件具有延迟运行效果。但会忽略 document.write 语句。
Chrome Safari Opera 不支持 defer 属性。
分析以下代码:
<html> <head> </head> <body> <div id="d1"></div> <div id="d2"></div> <script> var a1 = "<div>a1</div><script defer>alert('a1');<\/script>"; var a2 = "<script defer>alert('a2');<\/script>" document.getElementById("d1").innerHTML = a1; document.getElementById("d2").innerHTML = a2; </script> </body> </html>
上面代码中分别往【d1】和【d2】中通过 innerHTML 插入了一段 HTML 代码,且均包含有 SCRIPT 标签,SCRIPT 标签设置了 defer 属性。区别为【d1】中插入的 HTML 代码比【d2】中在最开始多了一个 DIV 元素。
在 IE 中只弹出了 "a1" 提示框,即只有字符串 "a1" 中的脚本执行。这是 IE 的一个 Bug,当 SCRIPT 元素为插入字符串的第一个元素时,即使按照 MSDN 所述为 SCRIPT 元素增加了 defer 属性后,该 SCRIPT 及之后的 SCRIPT 元素内的脚本也无法执行。
所以通常为了使 innerHTML 插入的脚本能够在 IE 中正常执行,经常会在欲插入的 HTML 代码字符串的最开始增加一个不可见的元素。如:
<span style="display:none;">span</span><script defer>alert('a1');<\/script>
接下来再看看 Firefox 中使 innerHTML 中的脚本执行的特殊方法:
分析以下代码:
<html> <head> </head> <body> <div id="d1"></div> <script> var a1 = "<script>alert('a1');<\/script>"; var d1 = document.getElementById("d1"); var sib = d1.nextSibling; var pn = d1.parentNode; pn.removeChild(d1); d1.innerHTML = a1; if (sib) { pn.insertBefore(d1, sib); } else { pn.appendChild(d1); } </script> </body> </html>
上面代码中,字符串 "a1" 中包含 SCRIPT 元素,接下来将待插入 HTML 代码的 DIV 元素【d1】从其父元素中移除,然后通过 innerHTML 将 "a1" 中的 HTML 代码插入到【d1】中,最后再将【d1】恢复至其原父元素中。
这段代码在 Firefox 中也成功的使 SCRIPT 中的脚本执行。
解决方案
上面提到的 IE 及 Firefox 中使通过 innerHTML 方法动态插入的 SCRIPT 元素中脚本执行的方法均比较特殊,是利用了浏览器的 Bug,或者是利用了浏览器提供的特性。而 innerHTML 方法只是用来插入 HTML 代码,并不能使其中包含的脚本代码执行。为了达到最好的兼容性,应避免利用浏览器特性及 Bug 使 innerHTML 插入的 SCRIPT 中的代码执行。所以上述 IE 和 Firefox 中的方法不可行。同时这种做法具有安全隐患。
对于可控来源的动态脚本,使用 createElement 创建 SCRIPT 元素并追加至页面的文档树中,以保证动态脚本的执行。
相关文章推荐
- BX9029: IE 和 Firefox 可以通过特定方法使 innerHTML 方法载入的 SCRIPT 标签中的 JavaScript 代码在页面加载后也可以执行
- 通过自定义原型来给moz-firefox下添加IE方法和属性
- magento后台无法通过IE登陆,但可以通过chrome和firefox登陆
- 其他浏览器(firefox,chrome)可以上网 ie(Internet Explorer)无法上网 解决方法
- extjs中的JS代码在firefox可以正常运行,在IE中无法运行的方法。
- extjs中的JS代码在firefox可以正常运行,在IE中无法运行的方法。
- 禁止浏览器后退的一种实现方法,在IE, Firefox, Safari, Chrom 和 Opera上测试通过
- IE和Firefox(火狐)在JavaScript方面的不兼容及统一方法总结
- 为什么有时IE不能加载背景图片而Firefox或Chrome都可以成功加载?
- firefox、IE下的几个不同属性的方法调用
- 判断iframe是否加载完毕的方法(兼容ie和Firefox)
- JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
- struts2 通过xml进行特定方法的验证
- windows8.1 打不开网页 除ie外打不开网页 firefox chrome 打不开网页解决方法
- javascript获取textarea光标选择位置和内容方法(IE, Firefox)
- firefox书签与IE收藏夹的互相导入乱码解决方法
- [转]兼容IE和Firefox的打开新窗口,关闭父窗口,不提示解决方法
- ul在Firefox和IE下的不同表现的解决方法
- 转:IE和Firefox的div高度自适应解决方法
- 解析IE, FireFox, Opera 浏览器支持Alpha透明的方法