【问题标题】:jQuery "loading" spinner stopped workingjQuery“加载”微调器停止工作
【发布时间】:2018-01-09 22:48:30
【问题描述】:

以下代码在我的 Rails 应用程序中运行了一段时间:

 $(function () {

     // Change the link's icon while the request is performing
     $(document).on('click', 'a[data-remote]', function () {
         var icon = $(this).find('i');
         icon.data('old-class', icon.attr('class'));
         icon.attr('class', 'glyphicon glyphicon-refresh spin');
     });

    // Change the link's icon back after it's finished.
    $(document).on('ajax:complete', function (e) {
        var icon = $(e.target).find('i');
        if (icon.data('old-class')) {
            icon.attr('class', icon.data('old-class'));
            icon.data('old-class', null);
        }
    })

}

代码用“刷新”字形图标替换一个字形图标并旋转它,直到 AJAX 请求完成,然后用原始字形图标替换它。

我最近注意到代码已停止工作。 AJAX 请求工作正常,但在 AJAX 调用期间我不再获得旋转刷新字形图标。升级到 Rails 5.1 可能会导致问题。

我的 Gemfile 中确实有 gem 'jquery-rails',所以我认为 Rails 5.1 升级是完全向后兼容的。可能是其他一些变化导致了这个问题。

我将第一个函数更新如下:

$('a[data-remote]').on('click', function () {
    var icon = $(this).find('i');
    icon.data('old-class', icon.attr('class'));
    icon.attr('class', 'glyphicon glyphicon-refresh spin');
});

这在第一次单击按钮时有效,但如果再次单击相同的按钮,我就没有微调器了。

有没有解决这个问题的方法,最好是使用标准的 DOM API?我搞砸了:

document.querySelectorAll('[data-remote]').onclick = function () { ... }

但没有任何运气。

我是否接近一个可行的答案?这会是使用 addEventListener 的好选择吗?

【问题讨论】:

  • 我无法重现您在 Rails 5.1 应用程序中观察到的行为。你在你的应用程序中使用Turbolinks 吗?如果是这样,您应该将 Javascript 包装在 $(document).on('turbolinks:load', function(){...}) 而不是 $(function(){...})
  • 我目前没有使用 Turbolinks。我想在以后使用它,但我想先解决这个问题。
  • 既然 Turbolinks 不是问题,还有其他想法为什么这不起作用?使用原始代码,我检查了按钮,并且没有添加事件处理程序。似乎最简单的解决方案是保留$(document).on('click', '???') 模式,但找到一种方法让它附加到现有按钮上,不是吗?
  • 我使用的是$(a[data-remote]) 模式,但在切换到$(document).on('click', ...) 时,我可以重现您提到的行为。
  • 绑定到body 而不是document 似乎实际上触发了监听器函数:$("body").on('click', ...)

标签: javascript jquery ruby-on-rails ajax


【解决方案1】:

@Jeff 可能是对的,您正在替换链接元素并失去侦听器。这不会是使用$(document).on('click', 'a[data-remote]', ...) 模式的问题,因为在声明事件处理程序之后添加到文档的元素上触发的事件 将被捕获(请参阅this question)。问题是似乎阻止链接click 事件冒泡到document,并且无法调用侦听器函数。

绑定到body 而不是document 似乎可以解决问题:

$("body").on('click', 'a[data-remote]', function () {
     var icon = $(this).find('i');
     icon.data('old-class', icon.attr('class'));
     icon.attr('class', 'glyphicon glyphicon-refresh spin');
 });

【讨论】:

  • 你认为这是 Rails 5.1 中无意的重大变化吗?
  • @moveson 我不确定,但如果$(document).on(...) 模式在您升级到 5.1 时停止工作,那么点击事件通过 DOM 冒泡的方式肯定发生了变化。
  • Rails 5.1 没有变化,因为这严格来说是一个 javascript 问题。您将侦听器绑定到元素上,一旦元素被替换,您也失去了侦听器。类比就像为汽车购买保险单。您拥有特定汽车的保单,但如果您不再拥有该汽车,该保单将毫无用处。将听者绑定到身体上,就相当于买了一份保护伞保险。无论您拥有什么汽车,保单仍应涵盖新车(在这种情况下为新元素)。
  • @Jeff 不应该绑定到document 有同样的效果吗?我们不确定为什么绑定到 body 有效,但绑定到 document 无效。
  • 我不确定为什么这不起作用,但最好的办法是在添加调试器的行之前放置一个调试器,以查看 $('document') 是否是您要查找的元素。然后在文档监听器中放一个调试器,看看它是否正在执行。
【解决方案2】:

您的 ajax 请求是否还会刷新具有原始侦听器的元素?发生的事情听起来像是听者不见了。

  1. $('a[data-remote]') 被点击,监听器告诉微调器旋转。

  2. AJAX 调用可能会替换页面上的某些元素,包括原始的 $('a[data-remote]') 元素。

因为在ajax页面加载/刷新后没有再次添加监听器,所以第二次点击按钮将不起作用。

只是一个假设,但您也可以在点击处理程序中添加 debugger 并打开 google chrome 扩展工具。查看每次单击按钮时脚本是否暂停。

基本修复更新:

function toggleIcons() {
  $('.regularIcon').toggle();
  $('.spinningIcon').toggle();
}

function toggleButtons() {
  $('.postButton').toggle();
  $('.deleteButton').toggle();
}

$('.postButton').click(function(e) {
  e.preventDefault();
  toggleIcons();

  // ajax call here
  $.ajax({
    type: "GET",
    url: "/route",
    data: data,
    dataType: "JSON",
  }).success(function(json) {
    toggleIcons();
    toggleButtons();
  })
});

// Listener for deleteButton
$('.deleteButton').click(function(e) {
  e.preventDefault();
  toggleIcons();

  // ajax call here
  $.ajax({
    type: "GET",
    url: "/route",
    data: data,
    dataType: "JSON",
  }).success(function(json) {
    toggleIcons();
    toggleButtons();
  })
});

依赖于您确保两个按钮在 DOM 上的相同位置设置样式。

【讨论】:

  • 是的,这似乎是问题所在。脚本仅在第一次单击按钮时暂停。替换后如何将处理程序添加回元素?
  • 你的模式不好,但如果你需要修复它,在 AJAX 请求的成功回调上,只需调用添加了上面你的侦听器的初始函数。 $('a[data-remote]').on('click', ....
  • 什么是更好的模式?页面上大约有 50 个按钮需要在页面首次加载时添加此事件处理程序。
  • 我可能会在元素上切换类。例如,单击$('a[data-remote]'),使用jQuery .hide() 隐藏“未加载”图标,然后在隐藏的微调器上调用.show()。然后当ajax调用完成后,只需反转即可。
  • 更正:我接受@w_hile 的回答,因为这解决了我的问题。对不起,我把名字弄混了。但是这两个答案都对我的理解很有帮助。
猜你喜欢
  • 1970-01-01
  • 2014-07-10
  • 1970-01-01
  • 2018-05-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多