停止页面在beforeunload事件处理程序中卸载

问题描述:

在用户浏览页面代码之前,检查他是否编辑了一些表单域。如果他这样做,我会显示一个带有YesNo按钮的模式窗口。如果他点击否,模式应该关闭并且用户保持在该窗口上。如果是 - 保存更改并卸载。停止页面在beforeunload事件处理程序中卸载

$(window).bind('beforeunload', function(){ 
     // check if any field is dirty 
     if ($('div.form').dirtyForms('isDirty')) { 
      var modalParams = { 
       Content: 'You have some unsaved changes, proceed?' 
       OnSave: navigateAndSave, 
       OnCancel: cancelNavigate 
      } 
      ShowModal(modalParams); 
     } 
    }) 

function navigateAndSave() { 
    // Do stuff 
}; 

function cancelNavigate() { 
    // Stop page from unloading and close the modal 
}; 

那么我能在cancelNavigate上做些什么来阻止页面的卸载?

+0

在将来,如果您对jQuery的肮脏的形式有任何疑问,您应该包括在问题jQuery的dirtyforms标签让你更容易获得足够的答案。 – NightOwl888

我相信你只需要在事件中调用preventDefault。

$(window).bind('beforeunload', function(e){ 
     // check if any field is dirty 
     if ($('div.form').dirtyForms('isDirty')) { 
      var modalParams = { 
       Content: 'You have some unsaved changes, proceed?' 
       OnSave: navigateAndSave, 
       OnCancel: e.preventDefault(); 
      } 
      ShowModal(modalParams); 
     } 
    }) 

function navigateAndSave() { 
    // Do stuff 
}; 

这是不可能的。

您仅限于显示文本消息以及在页面上继续或离开的选项。

请,看到此链接以获取更多信息:https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

window.onbeforeunload = funcRef 
  • funcRef是一个函数或功能表达的引用。
  • 函数应该为Event对象的returnValue属性指定一个字符串值并返回相同的字符串。

例子:

window.onbeforeunload = function(e) { 
    return 'Dialog text here.'; 
}; 

可以,之后用户决定留在页面上,显示你的语气,但我认为它的建议将在那时被击败。

如其他人所述,您可以通过监听页面上链接和窗体上的点击和键盘事件来拦截导航,但是当用户尝试手动输入URL时,不会显示任何对话框,请关闭选项卡,关闭窗口,按下重新加载,后退或前进按钮等。

beforeunload事件被设计为这种方式来保护用户免受恶意脚本攻击。

如果允许某种控制,某人可以将浏览器锁定在所需的页面中,但不允许您导航或关闭该窗口。

编辑:

我已经成功地显示一个确认对话框,作品几乎要通过连接到2个事件beforeunloadunload以同样的方式。它的工作原理上的Internet Explorer 11,火狐40和Safari 5.1的Windows(我现在能确认):

var alreadyTriggered = false; 
 

 
function onQuit() { 
 
    if (alreadyTriggered) return true; 
 
    alreadyTriggered = true; 
 

 
    if (confirm('Sure?')) { 
 
    alert('OK'); 
 
    } else { 
 
    alert('Cancel'); 
 
    } 
 
} 
 

 
window.onbeforeunload = onQuit; 
 
window.onunload = onQuit;
You can <a href="javascript: location.reload();">reload the page</a> to test it here.

这依赖于对JS事件循环中断的确认对话框原因,并且无法使用自定义对话框进行此项工作,因为在用户获得与其交互的机会之前,页面将会更改或关闭。

仍然没有办法避免页面更改或关闭,也无法使其在Chrome中运行。这在Firefox中也不起作用,事件不是由用户交互触发的。

+0

是它在某种程度上可以援引“离开此页面”,并自动取消这样呢? – Mefhisto1

+0

不幸的是,这也是不可能的。请记住,所有这些限制都是内涵安全措施。 – rcdmk

+0

Downvoting这一点,因为这是可能的肮脏的形式,它只是不与'beforeunload'事件可能。在用户尝试通过单击页面内的超链接来导航的情况下,脏表单能够显示GUI模式对话框。 – NightOwl888

这是可能的,但只有当用户单击页面内的超链接。如果用户使用浏览器远离页面,他们将得到默认浏览器对话框,该对话框没有保存选项。

肮脏的形式自动连接(和删除处理)到beforeunload事件,让你尝试创建另一个事件处理程序肯定会失败。使用脏表单时,绝不应该这样做。

你没有提到你想要使用哪种模式对话框框架,所以我只会使用jQuery UI对话框来展示一个例子。集成其他对话框框是类似的。为此,您可能需要查看existing pre-built dialogs的源代码。

此外,您的用例有点短。如果用户想要导航并忽略这些更改会怎么样?我添加了一个包含额外选项的示例。

<html> 
<head> 
    <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.ui/1.11.3/jquery-ui.min.css" /> 
</head> 
<body> 

    <script type="text/javascript" src="//cdn.jsdelivr.net/g/[email protected],[email protected],[email protected]"></script> 
    <script type="text/javascript"> 
    $(document).ready(function() { 
     // This is required by jQuery UI dialog 
     $('body').append('<div id="dirty-dialog" style="display:none;" />'); 

     // This must be called before the first call to .dirtyForms 
     $(document).bind('bind.dirtyforms', function (ev, events) { 
      var originalOnRefireClick = events.onRefireClick; 

      events.onRefireClick = function (ev) { 
       if (saveForm) { 
        // TODO: Replace this with your AJAX function 
        // to save the form. 
        alert('saving form...'); 
       } 
       originalOnRefireClick(ev); 
      }; 
     }); 

     // Flag indicating whether or not to save the form on close. 
     var saveForm = false; 

     $('.mainForm').dirtyForms({ 
      dialog: { 
       // Custom properties to allow overriding later using 
       // the syntax $.DirtyForms.dialog.title = 'custom title'; 

       title: 'Are you sure you want to do that?', 
       proceedAndSaveButtonText: 'Save Changes & Continue', 
       proceedAndCancelButtonText: 'Cancel Changes & Continue', 
       stayButtonText: 'Stay Here', 
       preMessageText: '<span class="ui-icon ui-icon-alert" style="float:left; margin:2px 7px 25px 0;"></span>', 
       postMessageText: '', 
       width: 650, 

       // Dirty Forms Methods 
       open: function (choice, message) { 
        $('#dirty-dialog').dialog({ 
         open: function() { 
          // Set the focus on close button. This takes care of the 
          // default action by the Enter key, ensuring a stay choice 
          // is made by default. 
          $(this).parents('.ui-dialog') 
            .find('.ui-dialog-buttonpane button:eq(2)') 
            .focus(); 
         }, 

         // Whenever the dialog closes, we commit the choice 
         close: choice.commit, 
         title: this.title, 
         width: this.width, 
         modal: true, 
         buttons: [ 
          { 
           text: this.proceedAndSaveButtonText, 
           click: function() { 
            // Indicate the choice is the proceed action 
            choice.proceed = true; 

            // Pass a custom flag to indicate to save the data first 
            // in the onRefireClick event 
            saveForm = true; 

            $(this).dialog('close'); 
           } 
          }, 
          { 
           text: this.proceedAndCancelButtonText, 
           click: function() { 
            // Indicate the choice is the proceed action 
            choice.proceed = true; 
            // Pass a custom flag to indicate not to save the data 
            // in the onRefireClick event 
            saveForm = false; 

            $(this).dialog('close'); 
           } 
          }, 
          { 
           text: this.stayButtonText, 
           click: function() { 
            // We don't need to take any action here because 
            // this will fire the close event handler and 
            // commit the choice (stay) for us automatically. 
            $(this).dialog('close'); 
           } 
          } 
         ] 
        }); 

        // Inject the content of the dialog using jQuery .html() method. 
        $('#dirty-dialog').html(this.preMessageText + message + this.postMessageText); 
       }, 
       close: function() { 
        // This is called by Dirty Forms when the 
        // Escape key is pressed, so we will close 
        // the dialog manually. This overrides the default 
        // Escape key behavior of jQuery UI, which would 
        // ordinarily not fire the close: event handler 
        // declared above. 
        $('#dirty-dialog').dialog('close'); 
       } 
      } 
     }); 
    }); 
    </script> 

    Change one of the fields below, then click "Go to Google" to try to navigate away. 

    <form class="mainForm" action="jqueryui.html"> 
     First name: <input type="text" name="fname"><br> 
     Last name: <input type="text" name="lname"><br> 
     <input type="submit" value="Submit"> 
    </form> 

    <a href="http://www.google.com/">Go to Google</a> 

</body> 
</html> 

的例子使用custom event binding附加到onRefireClick事件处理程序,它就会引发choice.proceed = true,但是当它是false不是。