我有一个使用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响应中:
我还检查了“网络”标签,以确保/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')+'">');
}
});
});
我提供了一笔赏金,因为这不是一个要解决的小问题-事实证明没有人给出可行的答案。我希望得到正确的答案:
setTimeout
或其他方式)。如果用户与HTML响应中之前中返回的UI元素(例如按钮)进行交互,则超时,因此触发了js……这只会导致我们现在遇到的相同问题。因此,就我而言,这不是有效的解决方案。几个人要求摆弄小提琴或演示。没有两个人会得到相同的结果-这是问题的关键-所以我本来不是一个人。返回的写入#ajaxContent
的HTML如下所示:http://jsfiddle.net/v4t9j32g/1/-这是浏览器中的ajax响应后显示的开发工具。请注意,返回的内容长度可能会有所不同,因为它是对关键字搜索工具的响应,它带回了许多过滤器按钮。另请注意,此HTML响应包含行<script src="/js/search_regulations.js"></script>
。 这就是有问题的js所在的位置,并且该问题的完整内容如上面在本问题中所示-包含console.log('search_regulations.js firing')
答案 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请求)和更好的代码可匹配性。
通常,我会在您的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)
因此,以下应解决您的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。
如果您好奇的话,这是我与该演示一起使用的脚本,该脚本稍作修改:
答案 3 :(得分:1)
可以使用HTML5 / jQuery或先前HTML版本和本机Javascript的组合来解决问题。使用jQuery之类的库的唯一原因是使旧版浏览器获得相同级别的支持或修复错误,并在一组开发人员之间共享一个标准框架。
另外,我认为,将解决问题所需的几行代码放在什么位置都没关系,它们可以放在页面的顶部,页面底部或经常重新加载的Ajax响应有效负载内的赏金要求。
真正的诀窍在于实现点击事件触发的方法,您选择在重复的Ajax响应中存在的脚本内执行此操作的选择,是使您的课程在某些时候失败的原因。
每次Ajax请求发生时,响应中的脚本都会添加新的事件侦听器。这些将不断总结,直到浏览器由于某种原因(内存不足,事件堆栈耗尽或click事件竞争条件)而失败为止。
因此,解决您的问题的方法是避免每次Ajax请求/响应发生时都添加事件。这项任务可以通过简单的“捕获阶段事件委托”(不幸的是很少使用)轻松解决。
事件侦听器仅在顶部节点之一上添加一次,该顶部节点可以是“文档”节点本身或“ html”元素或“ body”元素,因此在DOM之后始终存在的一个元素上初始页面加载。
此元素将负责捕获页面上当前存在或稍后加载的所有点击(通过您的Ajax请求),并且此元素将在页面的整个生命周期内起作用,否我需要一些建议来设置/销毁事件。嗯,这也许也可以工作,但是会在浏览器引擎上产生更多的工作量,消耗更多的内存,需要更多的代码,并且总的来说,它变慢了,而且至少可以说是棘手。
我为您设置了两个CodePen示例:
Delegation1在HEAD部分中具有事件处理代码,如果不存在任何限制或其他未知的怪癖,这是处理此类问题的首选方法。此版本的好处是代码更短/更快,更易于维护。
Delegation2在Ajax响应中具有事件处理代码,并且应满足有关连续加载HTML / JS的要求。只需勾选一次即可安装侦听器,并避免多个事件相互竞争和重叠。
示例中的Javascript代码包含相关注释,应足以解释所实施的策略,以使其尽可能简单并在其他类似情况下可重用。
这些示例是在考虑到较旧的浏览器的情况下编写的,较新的浏览器公开了功能更强大的API,例如element.matches(selector)
,对事件委托非常有用。我故意避免将其用于更广泛的支持。
答案 4 :(得分:0)
您需要从HTML中剥离