JavaScript基础教程之执行AJAX返回HTML片段中的JavaScript脚本
沉沙 2019-03-08 来源 : 阅读 816 评论 0

摘要:本篇文章探讨了JavaScript基础教程之执行AJAX返回HTML片段中的JavaScript脚本,希望阅读本篇文章以后大家有所收获,帮助大家对相关内容的理解更加深入。

本篇文章探讨了JavaScript基础教程之执行AJAX返回HTML片段中的JavaScript脚本,希望阅读本篇文章以后大家有所收获,帮助大家对相关内容的理解更加深入。

JavaScript基础教程之执行AJAX返回HTML片段中的JavaScript脚本

<


如果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=‘;
        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的脚本块是什么,你可以先临时注释这一行代码。
   

本文由职坐标整理发布,学习更多的相关知识,请关注职坐标IT知识库!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程