简体   繁体   English

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

[英]Stop page from unloading within the beforeunload event handler

Before user navigates the page code checks if he edited some of the form fields. 在用户浏览页面代码之前,请检查他是否编辑了某些表单字段。 If he did, I display a modal window with Yes and No buttons. 如果他这样做了,我将显示一个带有“ Yes和“ No按钮的模态窗口。 If he clicks no, modal should close and the user remains on that window. 如果他单击否,则应该关闭模式对话框,并且用户仍留在该窗口中。 If yes - save changes and unload. 如果是,请保存并卸载。

  $(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
};

So what can I do in cancelNavigate to stop the page from unloading? 那么,在cancelNavigate我可以做什么来阻止页面的卸载呢?

This is possible, but only if the user clicks a hyperlink within the page. 这是可行的,但前提是用户单击页面内的超链接。 If the user uses the browser to navigate away from the page, they will get the default browser dialog, which doesn't have an option to save. 如果用户使用浏览器离开页面,他们将获得默认的浏览器对话框,该对话框没有保存选项。

Dirty Forms automatically attaches (and removes the handler) to the beforeunload event, so your attempt to create another event handler will most certainly fail. 脏表单会自动附加(并删除处理程序)到beforeunload事件,因此您尝试创建另一个事件处理程序的尝试肯定会失败。 You should never do this when using Dirty Forms. 使用脏表单时,绝对不要这样做。

You didn't mention which modal dialog framework you wanted to use, so I will just show an example using jQuery UI dialog. 您没有提到要使用哪种模式对话框框架,因此我将仅显示一个使用jQuery UI对话框的示例。 Integrating other dialog frameworks is similar. 集成其他对话框框架是相似的。 To do so, you might want to check out the source code of the existing pre-built dialogs . 为此,您可能需要检出现有预建对话框的源代码。

Also, your use case is a bit short-sided. 另外,您的用例有点短。 What if the user wants to navigate away and ignore the changes? 如果用户想离开并忽略更改怎么办? I have added an example that includes an additional option to do just that. 我添加了一个示例,其中包括一个用于执行此操作的附加选项。

<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/jquery@1.11.3,jquery.ui@1.11.3,jquery.dirtyforms@2.0.0"></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>

The example uses custom event binding to attach to the onRefireClick event handler, which is fired when choice.proceed = true , but not when it is false . 该示例使用自定义事件绑定来附加到onRefireClick事件处理程序,该事件处理程序在choice.proceed = true时被激发,而在falsechoice.proceed = true被激发。

That's not possible. 那不可能

You are limited to show a text message along with the option to continue on the page or go away. 您只能显示短信以及继续在页面上显示或消失的选项。

Please, see this link for more information: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload 请查看此链接以获取更多信息: https : //developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

 window.onbeforeunload = funcRef 
  • funcRef is a reference to a function or a function expression. funcRef是对函数或函数表达式的引用。
  • The function should assign a string value to the returnValue property of the Event object and return the same string. 该函数应为Event对象的returnValue属性分配一个字符串值,并返回相同的字符串。

Example: 例:

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

You can, after the user decides to remain on the page, show your modal, but I think it's propose will be defeated at that time. 在用户决定保留在页面上之后,您可以显示您的模态,但是我认为建议那时会失败。

As stated by others, you can intercept navigation by listening to click and key events on links and forms on your page, but this will not allow you to show any dialog when the user tries to enter a URL manually, close the tab, close the window, press the reload, back or forward buttons, etc. 如其他人所述,您可以通过侦听页面上链接和表单上的单击和按键事件来拦截导航,但是当用户尝试手动输入URL,关闭标签,关闭导航栏时,这将不允许您显示任何对话框。窗口,按下重新加载,后退或前进按钮等。

The beforeunload event is designed this way to protect users from malicious scripts. beforeunload事件是通过这种方式设计的,可以保护用户免受恶意脚本的攻击。

If permitted that kind of control someone could lock your browser in a desired page, not allowing you to navigate away or close the window. 如果允许这种控制,则有人可以将您的浏览器锁定在所需的页面中,而不允许您浏览或关闭窗口。

Edit.: 编辑。:

I've managed to show a confirmation dialog that works almost the same way you want by attaching to the 2 events beforeunload and unload . 通过附加到2个事件beforeunloadunload我设法显示了一个确认对话框,其工作原理几乎与您想要的相同。 It works on Internet Explorer 11, Firefox 40 and Safari 5.1 for Windows (that I can confirm right now): 它适用于Windows的Internet Explorer 11,Firefox 40和Safari 5.1(我现在可以确认):

 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. 

This relies on the break on the JS event loop that the confirmation dialog causes and there is no way of making this work with custom dialogs because the page will change or close before the users gets the chance to interact with it. 这依赖于确认对话框导致的JS事件循环的中断,并且无法使用自定义对话框来完成此工作,因为页面将在用户有机会与之交互之前更改或关闭。

There is still no way to avoid the page to change or close and also no way to make this work in Chrome. 仍然无法避免页面更改或关闭,也无法在Chrome中实现此功能。 This will also not work in Firefox the event was not fired by an user interaction. 如果用户交互未触发该事件,则在Firefox中也将不起作用。

I believe you just need to call preventDefault on the event. 我相信您只需要在事件上调用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
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM