You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在用户离开表单后终止turbolinks:click事件监听器?

解决Rails表单未保存更改提醒的Turbolinks事件监听问题

你的核心问题在于匿名事件处理器无法精准移除,以及confirmationShown的状态逻辑错误,导致用户操作后监听器没有正确清理或重置。以下是修复后的完整实现:

<script>
  function unsavedChangesAlert() {
    let formChanged = false;
    let formSubmitted = false;
    let confirmationShown = false;

    // 表单选择器保持不变
    const formSelectors = [
      '.custom-control-input',
      '.gl_fields select',
      '.gl_fields input[type="checkbox"]',
      '.wc_fields select',
      '.wc_fields input.commaClass',
      '.wc_fields input[type="checkbox"]',
      '.auto_fields select',
      '.auto_fields input[type="checkbox"]',
      '.umb_fields select',
      '.umb_fields input[type="checkbox"]',
      '.pl_fields select',
      '.pl_fields input[type="checkbox"]',
      '.im_fields input.commaClass',
      '.oh_fields input.commaClass',
      '.gk_fields input.commaClass',
      '.cg_fields input.commaClass',
      '.pollution_fields input.commaClass',
      '.pollution_fields input[type="checkbox"]',
      '.re_fields input.commaClass',
      '.re_fields input[type="checkbox"]',
      '.ava_fields input.commaClass',
      '.ava_fields input[type="checkbox"]',
      '.db_fields input.commaClass',
      '.db_fields input[type="checkbox"]',
    ];

    const formInputs = document.querySelectorAll(formSelectors.join(', '));
    $(formInputs).on('change keydown input', function() {
      formChanged = true;
    });

    // beforeunload 逻辑保持不变
    $(window).on('beforeunload', function(event) {
      if (formChanged && !formSubmitted) {
        event.preventDefault();
        window.scrollTo(0, document.body.scrollHeight);
      }
    });

    $('#edit_ins_reqs_form').submit(function(){
      formSubmitted = true;
      // 表单提交后移除turbolinks监听器
      $(document).off('turbolinks:click', handleTurbolinksClick);
    });

    // 使用命名函数,方便精准移除监听器
    function handleTurbolinksClick(event) {
      const editForm = $('#edit_ins_reqs_form');
      if (!$(event.target).closest(editForm).length) {
        const saveButton = $(event.target).closest('.submit');
        if (!saveButton.length && !$(event.target).hasClass('submit')) {
          if (formChanged && !formSubmitted) {
            if (!confirmationShown) {
              confirmationShown = true;
              if (confirm('你有未保存的更改,确定要离开此页面吗?')) {
                // 用户确认离开,移除监听器
                $(document).off('turbolinks:click', handleTurbolinksClick);
              } else {
                // 用户取消离开,阻止跳转并重置状态
                event.preventDefault();
                $(window).scrollTop($(document).height());
                confirmationShown = false;
              }
            }
          } else {
            // 无未保存更改,直接离开,移除监听器
            $(document).off('turbolinks:click', handleTurbolinksClick);
          }
        }
      }
    }

    // 绑定命名的turbolinks点击事件
    $(document).on('turbolinks:click', handleTurbolinksClick);
  }

  $(document).on('turbolinks:load', function() { 
    unsavedChangesAlert();
  });
</script>

关键修复点说明:

  • 命名事件处理器:将原来的匿名函数改为handleTurbolinksClick,这样可以用$(document).off('turbolinks:click', handleTurbolinksClick)精准移除该监听器,不会影响其他可能存在的turbolinks:click事件。
  • 状态逻辑调整:
    • 用户确认离开(confirm返回true)时,立即移除监听器,避免后续点击再次触发弹窗。
    • 用户取消离开(confirm返回false)时,重置confirmationShown为false,确保下次操作仍能正常触发提醒。
  • 表单提交后清理:在表单提交成功的回调中移除监听器,因为此时已无未保存更改,无需再监听跳转行为。
  • 添加状态校验:只有在formChanged且!formSubmitted的情况下才触发提醒,避免不必要的弹窗。

内容的提问来源于stack exchange,提问作者ryanosull

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:38:08