[转]原文地址:http://www.cnblogs.com/webflash/archive/2010/01/04/1638621.html
如果AJAX加载的数据是一个HTML片段,而且这个HTML片段还包含脚本<script>块,那么在你把这数据xmlHttp.responseText用innerHTML方法插入到当前文档一个元素中,你会发现AJAX加载回来的脚本根本没有执行。这是AJAX开发中很常见的问题,如果你不是一直在用JavaScript框架做开发,相信你早就发现这个问题了。本文分析了两个解决办法,其中一个是讲解jQuery框架的实现。
一、 问题描述
下面举个简单的例子,演示问题所在。在下面的例子中,假设变量responseText就是AJAX加载的HTML片段数据,其中包含脚本弹出一条消息,用innerHTML方法插入ID为ajaxData的DIV中,你可能期望看到弹出那个消息框,结果你发现没有,问题就是这样。
<div id="ajaxData"></div> <script type="text/javascript"> var responseText = '<p>这是一个段落</p><script>alert("这是AJAX加载回来的脚本片段")</script>'; document.getElementById('ajaxData').innerHTML = responseText; </script>
二、两种解决办法
1、 利用JavaScript的eval方法执行脚本。
本方法的具体实现思路是把xmlHttp.responseText中的脚本都抽取出来,不管AJAX加载的HTML包含多少个脚本块,我们对找出来的脚本块都调用eval方法执行它即可。下面提供一个封装好的函数:
function executeScript(html) { var reg = /<script[^>]*>([^\x00]+)$/i; //对整段HTML片段按<\/script>拆分 var htmlBlock = html.split("<\/script>"); for (var i in htmlBlock) { var blocks;//匹配正则表达式的内容数组,blocks[1]就是真正的一段脚本内容,因为前面reg定义我们用了括号进行了捕获分组 if (blocks = htmlBlock[i].match(reg)) { //清除可能存在的注释标记,对于注释结尾-->可以忽略处理,eval一样能正常工作 var code = blocks[1].replace(/<!--/, ''); try { eval(code) //执行脚本 } catch (e) { } } } }
本方法的使用如下,对HTML用innerHTML方法添加到DOM,紧跟着调用executeScript方法执行脚本块:
document.getElementById("div1").innerHTML = xmlHttp.responseText; executeScript(xmlHttp.responseText);
显然这个方法还是存在缺陷的,如果xmlHttp.responseText包含像这样的外部脚本调用:
<script type="text/javascript" src="/js/common.js"></script>,executeScript方法不能再深入执行这个外部加载的脚本。
2、 学习并使用jQuery框架的实现
jQuery对于AJAX加载HTML,是最终在执行html(value)方法时把整个xmlHttp.responseText数据转换成DOM,然后利用DOM相关操作方法来找出里面的脚本,最后再把这些脚本插入到head中。具体原理也不好说,先举个最简单的例子,然后再分析一下大致思路。先看例子:
$.get('ajax.aspx', function(data) { $('#div1').html(data); });
现在假设上面ajax.aspx页面返回的是HTML片段,而且包含一个或多个脚本块,甚至外部脚本引用。div1是AJAX请求发起页的一个DIV标签的ID,整句代码实现的结果是加载ajax.aspx中的HTML填充到一个ID为div1的DIV标签中。
在匿名回调函数中通过typeof(data)可以发现data还是原始的字符串,即等同于xmlHttp.responseText,通过代码执行跟踪发现,对AJAX加载脚本片段的执行处理不在jQuery的AJAX模块代码中,而是在html(value)方法,即把一段包含脚本块的HTML字符串插入DOM时,由它负责抽出脚本进行调用处理。而html(value)方法其实又是调用了append(value)方法……,整个过程大概调用了以下方法,箭头代表调用这些方法的先后顺序:
html -> append -> domManip -> clean -> evalScript -> globalEval
其中clean方法特别关键,这个方法也是jQuery比较重要的方法,其中也涉及修复HTML错误(标签没有结束,表格结构调整等方法)处理脚本。而脚本的抽出也是在这里进行的。看看相关源代码(jQuery1.3.2):
if (fragment) { for (var i = 0; ret[i]; i++) { if (jQuery.nodeName(ret[i], "script") && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript")) { scripts.push(ret[i].parentNode ? ret[i].parentNode.removeChild(ret[i]) : ret[i]); } else { if (ret[i].nodeType === 1) ret.splice.apply(ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script")))); fragment.appendChild(ret[i]); } } return scripts; }
另外,在evalScript方法中我们还发现如下代码,这里是“同”步加载像<script type="text/javascript" src="/js/common.js"></script>这样的外部脚本,解决executeScript方法存在的一个缺陷:
if (elem.src) jQuery.ajax( { url: elem.src, async: false, dataType: "script" });
同时也发现如下代码,这段代码是把xmlHttp.responseText中的脚本删除,因为在这个方法中,jQuery是准备把抽取的脚本放入head区,所以删除可以避免最终的HTML出现重复的脚本块:
if (elem.parentNode) elem.parentNode.removeChild(elem);
最后,在globalEval方法中,发现head.removeChild( script );方法,就是把脚本插入head后马上又移除脚本标签,这也是避免因为重复执行html(value)方法在head区生成重复的脚本块。这个移除是不影响脚本执行的,同是也是不会清除脚本块中的相关变量值。显然,如果你想看看html(data)最终的执行结果,比如抽取后插入到head的脚本块是什么,你可以先临时注释这一行代码。
[转]原文地址:http://www.cnblogs.com/webflash/archive/2010/01/04/1638621.html
相关推荐
在下面的例子中,假设变量responseText就是AJAX加载的HTML片段数据,其中包含脚本弹出一条消息,用innerHTML方法插入ID为ajaxData的DIV中,你可能期望看到弹出那个消息框,结果你发现没有,问题就是这样。...
本文实例讲述了jQuery+ajax实现动态执行脚本的方法。分享给大家供大家参考。具体分析如下: 有时候,在页面初次加载时就取得所需的全部JavaScript也是没有必要的。具体需要取得哪个脚本,要视用户的操作而定。虽然...
Scripts\ 常用javascript脚本文件夹 jquery-1.4.1-vsdoc.js jquery智能感知引用 jquery-1.4.1.js jquery一用文件 jquery-1.4.1.min.js jquery精简版 Styles\ 样式文件夹 Site.css 样式文件 ...
如果在你的WEB项目中,有很多地方都需要输出像下面这样的一个列表HTML: 代码如下: <ul> <li>JavaScript事件冒泡应用实例</li> 执行AJAX返回HTML片段中的JavaScript脚本</li> </ul> 很显然这是一个LI结构,也许你...
用ajax函数读取xml,然后解析XML.html,ajax无刷新读取文件,先使用jQuery加载XML,然后建立一个代码片段,遍历所有student节点,获取id节点,获取节点文本,获取student下的email属性,构造HTML字符串,通过append...
1.3 JavaScript语法中常见的陷阱 1.3.1 区分大小写 1.3.2 单引号与双引号 1.3.3 换行 1.3.4 可选的分号和花括号 1.3.5 重载(并非真正的重载) 1.3.6 匿名函数 1.3.7 作用域...
一组有用的脚本、片段和咒语,使互联网变得更美好。 目录结构 javascript ajax_post : 使用 ajax 发布到 PHP 文件(XMLHttpRequest 对象返回数据) button_marker : 动画菜单按钮标记 countdown_timer : 倒计时...
1.Ajax Rain AjaxRain有很多完美整合AJAX, CSS, DHTML 或 Javascript的实例...MiniAJAX 是一个新生的网站,收集了少许 DHTML 和 AJAX 脚本, 它的代码片段风格非常实用。 4.Ajaxian 一个接近于门户类型的AJAX
1.3 JavaScript语法中常见的陷阱 1.3.1 区分大小写 1.3.2 单引号与双引号 1.3.3 换行 1.3.4 可选的分号和花括号 1.3.5 重载(并非真正的重载) 1.3.6 匿名函数 1.3.7 作用域...
1.3 JavaScript语法中常见的陷阱 1.3.1 区分大小写 1.3.2 单引号与双引号 1.3.3 换行 1.3.4 可选的分号和花括号 1.3.5 重载(并非真正的重载) 1.3.6 匿名函数 1.3.7 作用域...
Ajax控件和类库现在真的太多了,不知不觉中增加了Ajax的神秘性和复杂...这段文本可以是xml格式,也可以是一个Html片段,也可以是一段JavaScript脚本,或者仅是一个字符串。服务器端仅仅是作为一个数据接口,客户端使用
摘要:脚本资源,Ajax/JavaScript,ajax无刷新读取文件 用ajax函数读取xml,然后解析XML.html,ajax无刷新读取文件,先使用jQuery加载XML,然后建立一个代码片段,遍历所有student节点,获取id节点,获取节点文本,获取...
“$.parseHTML”也提供了一种方式将HTML解析为DOM片段,并控制可能包含的任何脚本的执行。这对于由Content Security Policy (CSP)控制的JavaScript环境来说特别重要,因为注入的脚本可能导致安全警告或异常。 在...
成功完成所有请求后,将从每个ajax结果中提取HTML响应,并将其作为参数传递给解析,并以与给定url相同的顺序返回给调用方。用法使用插件相当容易。 给定经典的QUnit测试设置,我们需要添加脚本以在测试HTML设置中...
“$.parseHTML”也提供了一种方式将HTML解析为DOM片段,并控制可能包含的任何脚本的执行。这对于由Content Security Policy (CSP)控制的JavaScript环境来说特别重要,因为注入的脚本可能导致安全警告或异常。 在...
HTML中用于描述功能的符号称为"标记" 标记在使用时,用尖括号 "<>",标记的分类 1、封闭类型的标记 也称为 "双标记" , 必须成对出现 语法:<标记>内容标记> Demo : 1、创建 p 标记 --<p>...</p> 2、创建 ...
ServiceNow-语法编辑器宏:vargr JavaScript执行编辑器:在表单中,按启动Javascript Executor JavaScript Log&Field Watcher 我们想要什么:精明的UI编辑器Intellisense自动完成推荐工具:Sublime 2编辑器-用于对...
《高性能网站建设指南》一书介绍了如何针对网站中的Ajax、CSS、JavaScript、Flash和图片进行性能优化。每个性能规则都提供了示例,在本书的配套网站上可以找到代码片段。这些规则包括: •减少HTTP请求 •使用...