如何在用户离开表单后终止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
相关产品推荐
相关产品推荐

