执行Ajax响应内返回的js文件

时间:2018-07-20 11:25:25

标签: javascript jquery html ajax

我有一个使用jquery 3.2.1的HTML5应用程序。

在应用程序的一部分中-搜索功能-我提出了ajax请求。来自ajax请求的响应是HTML,其中包括一个<script>标记,该标记链接到与该应用程序位于同一服务器上的js文件。

所以ajax代码如下所示-用于发出ajax请求并将响应写入ID为#ajaxContent的div:

$.ajax({
    url: $('#searchRegulations').attr('action'),
    type: 'post',
    cache: false,
    data: $('#searchRegulations').serialize()
 }).done(function (response, status, xhr) {
        if (response) {
            $('main .content').hide();
            $('#ajaxContent').html(response).show();
            return false;
        }
    }
});

如果我检查#ajaxContent,我会发现<script>标签已包含在ajax响应中:

enter image description here

我还检查了“网络”标签,以确保/js/search_regulations.js的加载正确,并且给出200响应:

search_regulations.js内有一些jquery可以切换#ajaxContent中存在的某些过滤器。

  

问题是该代码似乎只在大约50%的范围内起作用   时间。当它起作用时,它将切换某些过滤器的状态   通过向类中的元素添加/删除类.active按钮   .browse-ctp__filters-data,然后将它们写为隐藏形式   ID #tmpFilters

为确保脚本“触发”,我在console.log('search_regulations.js firing');行中添加了一个代码,并确保每次每次都会在控制台中显示该脚本,而不管脚本是否起作用。

奇怪的是,如果在将ajax响应写入页面后将代码剪切/粘贴到控制台中,它会始终有效

将脚本带入页面的方式是否有问题?

我在下面粘贴了脚本,但是我认为这不是代码中的问题,而是浏览器/ ajax响应的处理方式:

$(function() {  

console.log('search_regulations.js firing');

/* toggle the active (applied) state on browse by filters */
/* @link https://stackoverflow.com/questions/48662677/switch-active-class-between-groups-of-include-exclude-buttons */
$(document).on('click', '.browse-ctp__filters-data .include, .exclude', function(){

    var $this = $(this);

    // Split name into array (e.g. "find_355" == ["find", "355"]) 
    var arr = $this.attr('name').split('_');


    // Toggle active class
    $this.toggleClass("active");
    if ($this.siblings().hasClass("active")) {
      $this.siblings().removeClass("active")
    }

    // Remove any existing instances of the filter from hidden form
    $('#tmpFilters input[value="exclude_'+arr[1]+'"]').remove();
    $('#tmpFilters input[value="find_'+arr[1]+'"]').remove();

    // If a filter has been applied then add it to hidden form
    if ($this.hasClass('active')) {
        $('#tmpFilters').append('<input type="hidden" name="tmpFilter[]" value="'+$this.attr('name')+'">');
    }
});    
}); 

关于提供赏金的注意事项:

我提供了一笔赏金,因为这不是一个要解决的小问题-事实证明没有人给出可行的答案。我希望得到正确的答案:

  1. 可与jsfiddle或同等功能论证。
  2. 说明其工作方式/原因。
  3. 了解ajax响应是HTML和js。 js作用于响应中的HTML元素。因此,两者都需要在响应中包括HTML和js-而不是说“只是将js添加到全局文件中”(我不希望js是全局的,因为它是特定的给定的HTML响应,并且可能在应用程序的不同部分有所不同。
  4. 不应使用超时(setTimeout或其他方式)。如果用户与HTML响应中之前中返回的UI元素(例如按钮)进行交互,则超时,因此触发了js……这只会导致我们现在遇到的相同问题。因此,就我而言,这不是有效的解决方案。
  5. 如果无法在HTML5 / jquery中解决此问题,请解释原因并提出其他解决方法。

jsfiddle显示通过ajax返回的HTML和脚本标签:

几个人要求摆弄小提琴或演示。没有两个人会得到相同的结果-这是问题的关键-所以我本来不是一个人。返回的写入#ajaxContent的HTML如下所示:http://jsfiddle.net/v4t9j32g/1/-这是浏览器中的ajax响应后显示的开发工具。请注意,返回的内容长度可能会有所不同,因为它是对关键字搜索工具的响应,它带回了许多过滤器按钮。另请注意,此HTML响应包含行<script src="/js/search_regulations.js"></script>这就是有问题的js所在的位置,并且该问题的完整内容如上面在本问题中所示-包含console.log('search_regulations.js firing')

的位

8 个答案:

答案 0 :(得分:4)

我看到的问题之一是您将onclick绑定到相同元素多次...

由于可以通过ajax请求多次加载js,因此在再次附加事件之前首先分离非常重要。

另一个问题是,您正在$(document).ready事件中运行代码(即,加载HTML文档并且DOM准备就绪时),但是最好在以下位置运行代码$(window).load事件(在完全加载完整页面(包括所有框架,对象和图像)时,会稍晚执行一次

示例

$(window).load(function() {  

    console.log('search_regulations.js firing');

    //off: detach the events
    //on: attach the events
    $('.browse-ctp__filters-data .include, .exclude').off('click').on('click', function(){
        ...
    }
}); 

答案 1 :(得分:1)

除了大家在评论中都在谈论什么之外,我将尝试将其回答。

事件驱动

JS是事件驱动的,这并不意味着您必须即时加载脚本以使它们在事件触发时执行功能。更好的方法是在页面加载时加载您需要的所有内容,并添加事件侦听器,这样可以提供更好的用户体验(更少的http请求)和更好的代码可匹配性。

TL; DR

通常,我会在您的html文件中执行以下操作:

<script src="/js/main.js">  
<script src="/js/search_regulations.js" async>  <!-- bonus tip! google "async script tag" -->

这将加载您需要的所有js。

请记住,search_regulations.js应该使用jQuery on方法添加所需的事件监听器,但是由于脚本添加事件监听器时html不存在,因此您可能需要检查{ {3}}。

为什么这样更好?

  • 现在,您可以很容易地将一个文件加载到另一个文件。将来,您可能想添加更多功能和更复杂的代码。当您具有相互加载的脚本链时,调试起来会很痛苦。
  • 如果用户在移动网络上,则必须等到加载search_regulations.js文件的请求后,该文件才会变大,这可能会带来糟糕的用户体验。
  • 您仍然可以使用search_regulations.js
  • 在应用程序上重用代码

答案 2 :(得分:1)

注意:

  • @ bastos.sergios已经回答了您的问题-请参阅他的第一点。
  • 还应将@ yts的信用额授予“加强”巴斯托斯的答案。

因此,以下应解决您的search_regulations.js脚本问题:

$(document)
  // Detach the event handler to prevent multiple/repeat triggers on the target elements.
  .off('click.toggleActive', '.browse-ctp__filters-data .include, .exclude')
  // Attach/re-attach the handler.
  .on('click.toggleActive', '.browse-ctp__filters-data .include, .exclude', function(){
    ... put your code here ...
  });

但是我写这个答案的主要意图是让你see the problem with your script

如果您好奇的话,这是我与该演示一起使用的脚本,该脚本稍作修改:

https://codepen.io/anon/pen/RBjPjw.js

答案 3 :(得分:1)

关于要求

可以使用HTML5 / jQuery或先前HTML版本和本机Javascript的组合来解决问题。使用jQuery之类的库的唯一原因是使旧版浏览器获得相同级别的支持或修复错误,并在一组开发人员之间共享一个标准框架。

另外,我认为,将解决问题所需的几行代码放在什么位置都没关系,它们可以放在页面的顶部,页面底部或经常重新加载的Ajax响应有效负载内的赏金要求。

关于问题

真正的诀窍在于实现点击事件触发的方法,您选择在重复的Ajax响应中存在的脚本内执行此操作的选择,是使您的课程在某些时候失败的原因。

每次Ajax请求发生时,响应中的脚本都会添加新的事件侦听器。这些将不断总结,直到浏览器由于某种原因(内存不足,事件堆栈耗尽或click事件竞争条件)而失败为止。

关于解决方案

因此,解决您的问题的方法是避免每次Ajax请求/响应发生时都添加事件。这项任务可以通过简单的“捕获阶段事件委托”(不幸的是很少使用)轻松解决。

事件侦听器仅在顶部节点之一上添加一次,该顶部节点可以是“文档”节点本身或“ html”元素或“ body”元素,因此在DOM之后始终存在的一个元素上初始页面加载。

此元素将负责捕获页面上当前存在或稍后加载的所有点击(通过您的Ajax请求),并且此元素将在页面的整个生命周期内起作用,否我需要一些建议来设置/销毁事件。嗯,这也许也可以工作,但是会在浏览器引擎上产生更多的工作量,消耗更多的内存,需要更多的代码,并且总的来说,它变慢了,而且至少可以说是棘手。

代码示例

我为您设置了两个CodePen示例:

Delegation1在HEAD部分中具有事件处理代码,如果不存在任何限制或其他未知的怪癖,这是处理此类问题的首选方法。此版本的好处是代码更短/更快,更易于维护。

Delegation1

Delegation2在Ajax响应中具有事件处理代码,并且应满足有关连续加载HTML / JS的要求。只需勾选一次即可安装侦听器,并避免多个事件相互竞争和重叠。

Delegation2

示例中的Javascript代码包含相关注释,应足以解释所实施的策略,以使其尽可能简单并在其他类似情况下可重用。

这些示例是在考虑到较旧的浏览器的情况下编写的,较新的浏览器公开了功能更强大的API,例如element.matches(selector),对事件委托非常有用。我故意避免将其用于更广泛的支持。

答案 4 :(得分:0)

您需要从HTML中剥离