[转]原文地址: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中,你可能期望看到弹出那个消息框,结果你发现没有,问题就是这样。...
这个"个人JavaScript脚本收藏"压缩包文件显然包含了作者收集的各种JavaScript代码片段和特效,旨在帮助开发者快速实现特定的功能或者提升网页的用户体验。 1. **基础概念**:JavaScript基于ECMAScript规范,它主要...
JavaScript脚本集合通常包括各种常用的、实用的代码片段,帮助开发者快速实现特定功能,提高开发效率。以下是一些JavaScript脚本集合中的核心知识点: 1. **基础语法**:JavaScript的基础包括变量声明(var, let, ...
**Ajax(Asynchronous JavaScript and XML)**是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。它通过在后台与服务器进行少量数据交换,使网页实现异步更新。这一技术的核心在于JavaScript,它允许...
在这个名为“网页常用jsp脚本”的压缩包中,包含了二百多个常用的JSP脚本代码片段,这些都是为了提高网页开发效率和性能而设计的。 首先,我们需要了解JavaScript的基本概念。JavaScript是一种解释型、轻量级、面向...
在提供的"js脚本集合"中,包含了100多个经典常用的JavaScript脚本。这些脚本可能是用于解决各种常见问题的函数库、工具集或者特定功能的实现,例如页面动态效果、表单验证、图片轮播、时间日期处理、Ajax请求等。...
标题中的“自我介绍与javascript脚本”表明了这个压缩包包含两部分主要内容:个人的自我介绍和JavaScript编程的练习或示例。JavaScript是一种广泛应用于网页和网络应用开发的编程语言,它主要负责网页的交互性,使...
JavaScript脚本是网页开发中的重要组成部分,主要用于实现交互性和动态效果。这个压缩包包含了342个JavaScript编码实例,虽然可能是一些过期的资源,但它们仍然能为我们提供宝贵的编程经验,帮助我们理解JavaScript...
综上所述,通过结合JavaScript切片技术与脚本执行引擎的互操作能力,可以有效地解决AJAX框架中URL解析的问题,进而实现更为强大的网络爬虫功能。这种方法不仅能够提高爬虫的工作效率,还能够显著提升其在面对现代Web...
这个"常用javascript脚本,网站开发人员的手册"显然是一份对于JavaScript开发者至关重要的资源,它可能包含了各种实用的代码片段、技巧以及最佳实践。 JavaScript是一种解释型的、面向对象的、弱类型的脚本语言,它...
这是因为默认情况下,Ajax加载的HTML片段被视为静态内容,浏览器不会执行其中的脚本。本文将详细讲解这个问题的解决方法。 首先,我们要了解为什么动态加载的JavaScript不被执行。当HTML通过Ajax加载时,浏览器并不...
1. **JavaScript**:客户端的脚本语言,用于创建和执行 Ajax 请求。在JavaScript中,XMLHttpRequest对象是实现Ajax的核心,它允许我们向服务器发送HTTP请求,并处理返回的数据。 2. **创建 XMLHttpRequest 对象**:...
2. **JavaScript脚本**:定义具体的Ajax请求逻辑,包括数据打包和发送方式。 3. **服务器端处理**:处理Ajax请求,执行相应的业务逻辑,并返回响应数据。 4. **响应处理**:解析服务器返回的数据,并根据需要更新...
服务器端的CakePHP控制器将接收这些数据并进行相应的处理,最终可能返回JSON格式的数据或直接返回HTML片段,由前端JavaScript解析后更新到页面上的指定位置。 通过以上知识点的掌握,开发者可以有效地在CakePHP框架...
3. **scripts**:此文件夹可能包含JavaScript脚本,包括实现Ajax请求和DOM操作的代码。 在`tabbed.html`中,开发者通常会使用`<div>`标签创建标签页容器,每个标签页是一个子`<div>`,并且设置相应的ID或类名以便...
在这个场景中,JavaScript用于创建和触发AJAX请求,以及处理服务器返回的结果。 3. **客户端验证**:客户端验证是Web应用程序中的一种常见实践,用于在用户提交数据之前检查其有效性。这可以通过JavaScript实现,...
1. **JavaScript基础**:JavaScript是一种广泛使用的脚本语言,主要用于网页和网络应用。它处理变量、数据类型、运算符、流程控制(如条件语句和循环)以及函数,这些都是JavaScript的基础。 2. **DOM操作**:文档...
// 脚本加载完成后执行的回调 }); ``` **三、jQuery与Struts2的Ajax整合** 在Struts2框架中,我们可以利用jQuery的Ajax功能进行数据交互。Struts2提供了JSON结果类型,方便与前端的Ajax请求配合。首先,你需要...
通过一个简洁易用的Ajax类,开发者可以方便地在前端HTML表单中触发Ajax请求,并在后端PHP脚本处理请求后,使用JavaScript更新页面内容,提高用户体验,避免了传统页面刷新带来的延迟感和打断感。在实际应用中,这种...