热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

让插入到innerHTML中的script跑起来的代码第1/2页

让插入到innerHTML中的script跑起来的代码
在做 ajax 编程时,我们常常需要将 xmlhttp 获取到的页面内容通过 innerHTML 来赋给某个容器(比如 div、span 或者 td 等),但是这里存在一个问题,就是我们将要赋给 innerHTML 的页面内容如果包含有脚本程序,这些脚本程序不管是外部脚本,还是内部脚本,可能(1)都不会被执行。这个问题在某些时候微不足道,甚至可以忽略,但有些时候,这个问题就非常严重,它很可能让我们的程序得不到预期的结果。因此我们需要解决这个问题。

如果你读过 MSDN,你会发现并非所有插入到 innerHTML 中的脚本都不能执行,如果这段脚本的 script 标签中包含了 defer 属性,IE 会正确的执行这些脚本程序。但不幸的是,Moziila/Firefox 和 Opera 可不吃这一套,不管 script 标签有没有设置 defer 属性,这些浏览器都不会向 IE 那样去执行插入到 innerHTML 中的脚本。

但不管脚本是否被执行了,有一点我们可以肯定,那就是这些脚本确实被插入到了 innerHTML 中,如果不相信,你可以 alert 一下看看。但如果你真的 alert 了,你也可能会发现有一种例外情况存在,那就是如果脚本在 innerHTML 内容开头的话,那么 IE 浏览器将会忽略掉这段脚本,而 Moziila/Firefox 和 Opera 却不会。

好了,问题分析的差不多了,我们来看看如何解决吧。

解决的思路其实很简单,那就是将插入到 innerHTML 中的所有脚本取出来,然后一一执行。不过我们先要解决上面的两个问题。

先来看第一个问题,如何避免在 IE 中重复执行 innerHTML 中带有 defer 属性的脚本。这个很容易,只需要先确定浏览器是否是 IE,然后再检测将要执行的脚本是否带有 defer 属性即可。需要注意的是,在判断 IE 浏览器时,我们需要避免被 opera 的浏览器识别欺骗。这一点我们在后面的代码中将会看到它是如何做的。

接下来,看 IE 忽略 innerHTML 开头脚本的问题,这个也很容易解决。只需要在要插入到 innerHTML 中的内容的开头附加一段不是脚本的内容,就可以了。但不要试图附加一个空内容的标签,或者空格、回车、换行等,这将不起作用,开头的脚本仍然会被忽略。也不要试图附加  ,虽然这可以让开头的脚本不再被忽略,但这个   仍然会影响原有内容的显示,虽然你可能觉得不明显,但是对于挑剔的用户来说,这可能是无法容忍的。因此,为了让附加的内容既可以起到避免开头脚本被忽略的功能,又不会造成不良影响,我们将附加这么一段内容:

hack ie
虽然上面这段内容有一定的长度,但是它并不会显示,而且这个插入的标签没有 id 也没有 name,所以也不会跟原来内容中的某些标签的 id 或者 name 产生冲突。不过这里有一点要注意,这里也要判断是否是 IE,然后再决定加不加这段内容,因为其他某些浏览器可能不支持 display: none 这个 CSS 修饰(例如 Opera Mini),如果加上这段代码会影响最终的显示效果。

下面我们来看看如何取出脚本并执行。

取出脚本很容易,只需要用 innerHTML 所在对象的 getElementsByTagName 方法就可以了,这个方法对几乎所有的容器标签都管用。取出脚本以后,我们要一一判断它们是外部脚本还是内部脚本。

先来看外部脚本,如果是外部脚本,我们选择了这样一种方法,即先创建这个外部脚本的一个副本对象,并设置它的 defer 属性为 true(这一点是为了让 IE 浏览器能正确执行),然后用 appendChild 方法将这个副本对象插入到 head 中。这里你可能会问,为什么不是插入到 innerHTML 所在的对象中呢?插入到 innerHTML 所在的对象中不是更好吗?如果你试一下就会知道,如果插入到 innerHTML 所在的对象中,在 IE 浏览器中没有问题,但是在 Mozilla/Firefox 和 Opera 浏览器中会有一些问题。问题是如果在 Firefox 上这样做,浏览器会停止响应(这是在 Firefox 1.5 上的测试结果,其他版本是否有此问题,尚不得知),而在 Opera 上,脚本会莫名其妙的执行两次(这是在 Opera 8.5 上的测试结果,其它版本的 Opera 是否由此问题,也尚不得知)。为了避免这些问题,所以我选择了插入到 head 中。

再来看内部脚本,内部脚本的内容我们可以直接用脚本对象的 text 属性来获取,这里我们使用脚本对象的 text 属性而不是 innerHTML 属性,是因为在 Opera 浏览器中,脚本对象的 innerHTML 属性是空的,只有用 text 属性才能获取到脚本内容。执行内部脚本直接用 eval 即可。但是脚本可能会被包含在 HTML 的注释标签中,因此我们需要先将注释标签去掉,不然在 IE 中会出错。

上面的分析看上去很完美了,但是实际上还是有问题,一个是 document.write 和 document.writeln 的问题,这个问题在 Blueidea 上,bound0 给出了一个思路,就是替换掉默认的 document.write 和 document.writeln 方法,不过他用的是字符串替换,因此只对内部脚本有效,对外部脚本就没办法了,因此我想了个更通用的办法,就是直接把 document.write 和 document.writeln 重新定义,这样不管内部脚本还是外部脚本执行的就都是我们我们自己定义的 document.write 和 document.writeln 了。不过也有副作用,就是这两个函数在当前页面中就不能再像原来一样使用了,不过这两个函数在页面加载完之后一般是不会再用到了,因此这里重新定义它们所带来的副作用影响很小。但是还有个问题是,尽管这样,我们仍然无法保证 document.write 或 document.writeln 输出的内容会显示在最合适的位置,它只是把内容附加到了我们放置内容的容器中。

另一个问题是 eval 引起的问题,一个是 Blueidea 上的 hutia 说的作用域的问题,另一个问题是如果用 eval 执行的内部脚本的话,内部脚本会在外部脚本加载完之前就开始执行了。要解决这个两个问题可以采用 window.setTimeout 这个函数,让每个脚本都延时一段后再执行,外部脚本延时时间可以设的较长,以保证其能够完全加载,而内部脚本则可以设置为很短,因为一个脚本执行的时间通常是很短的,这样既可以保证不会改变作用域,又可以基本保证脚本执行顺序不会改变了(这种方法对于保证执行顺序上也不一定会 100% 有效,如果网络非常繁忙,外部脚本可能在设置的时间内加载不完,但至少比直接用 eval 的时候好多了)。

——————————–
(1) 注:在这里,我们用了限定词“可能”,因为有一种情况,脚本会被执行,在下文中你将会看到这种情况。

12下一页阅读全文

推荐阅读
  • 一个登陆界面
    预览截图html部分123456789101112用户登入1314邮箱名称邮箱为空15密码密码为空16登 ... [详细]
  • 自己用过的一些比较有用的css3新属性【HTML】
    web前端|html教程自己用过的一些比较用的css3新属性web前端-html教程css3刚推出不久,虽然大多数的css3属性在很多流行的浏览器中不支持,但我个人觉得还是要尽量开 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 作为一名专业的Web前端工程师,掌握HTML和CSS的命名规范是至关重要的。良好的命名习惯不仅有助于提高代码的可读性和维护性,还能促进团队协作。本文将详细介绍Web前端开发中常用的HTML和CSS命名规范,并提供实用的建议。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 本文介绍了多个关于JavaScript的书籍资源、实用工具和编程实例,涵盖从入门到进阶的各个阶段,帮助读者全面提升JavaScript编程能力。 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 本文详细介绍超文本标记语言(HTML)的基本概念与语法结构。HTML是构建网页的核心语言,通过标记标签描述页面内容,帮助开发者创建结构化、语义化的Web页面。 ... [详细]
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
author-avatar
一粒星尘ch
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有