在离开未保存的更改的网页之前警告用户

我的应用程序中有一些带有表单的页面。

我如何确保表单的安全,如果有人浏览或closures浏览器标签,应该提示他们确认他们确实想要将表单保留为未保存的数据?

简短,错误的答案:

您可以通过处理beforeunload事件并返回一个非空string来完成此操作 :

 window.addEventListener("beforeunload", function (e) { var confirmationMessage = 'It looks like you have been editing something. ' + 'If you leave before saving, your changes will be lost.'; (e || window.event).returnValue = confirmationMessage; //Gecko + IE return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc. }); 

这种方法的问题是, 提交表单也触发卸载事件 。 通过添加您提交表单的标志可以很容易地解决这个问题:

 var formSubmitting = false; var setFormSubmitting = function() { formSubmitting = true; }; window.onload = function() { window.addEventListener("beforeunload", function (e) { if (formSubmitting) { return undefined; } var confirmationMessage = 'It looks like you have been editing something. ' + 'If you leave before saving, your changes will be lost.'; (e || window.event).returnValue = confirmationMessage; //Gecko + IE return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc. }); }; 

然后在提交时调用setter:

 <form method="post" onsubmit="setFormSubmitting()"> <input type="submit" /> </form> 

但是阅读…

长,正确答案:

当用户没有更改表单上的任何内容时,您也不希望显示此消息。 一种解决方法是将beforeunload事件与“脏”标志结合使用,只有在触发提示时才会触发提示。

 var isDirty = function() { return false; } window.onload = function() { window.addEventListener("beforeunload", function (e) { if (formSubmitting || !isDirty()) { return undefined; } var confirmationMessage = 'It looks like you have been editing something. ' + 'If you leave before saving, your changes will be lost.'; (e || window.event).returnValue = confirmationMessage; //Gecko + IE return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc. }); }; 

现在要实现isDirty方法,有很多种方法。

你可以使用jQuery和表单序列化 ,但这种方法有一些缺陷。 首先,你必须改变代码来处理任何forms( $("form").each()将会这样做),但最大的问题是,jQuery的serialize()只能用于已命名的,非禁用的元素,所以改变任何禁用或未命名的元素都不会触发脏标志。 有解决方法 ,就像使控制只读,而不是启用,序列化,然后再次禁用控件。

所以事情似乎要走了。 你可以尝试听按键 。 这个事件有几个问题:

  • 不会触发checkbox,单选button或其他通过鼠标input进行更改的元素。
  • 将触发不相关的按键,如Ctrl键。
  • 不会触发通过JavaScript代码设置的值。
  • 不会触发通过上下文菜单剪切或粘贴文本。
  • 对于像datepickers或checkbox / radiobutton这样的虚拟input,它们不能用于通过JavaScript将其值保存在隐藏input中。

change事件也不会触发JavaScript代码设置的值 ,所以也不适用于虚拟input。

input事件绑定到页面上的所有input (以及textareaselect s) 在旧浏览器上将不起作用,并且像上面提到的所有事件处理解决scheme一样,不支持撤销。 当用户更改文本框,然后撤消,或者选中或取消选中checkbox时,表单仍被认为是脏的。

而当你想要实现更多的行为,比如忽略某些元素,你就有更多的工作要做。

不要重新发明轮子:

所以,在你考虑实施这些解决scheme和所有必要的解决方法之前,要意识到你正在重新发明轮子,而且你很容易遇到别人已经为你解决的问题。

如果您的应用程序已经使用jQuery,那么您最好使用经过testing的代码,而不是自己编写代码,并使用第三方库来完成所有这些工作。 jQuery的你确定吗? 插件效果很好,看他们的演示页面 。 这很简单:

 <script src="jquery.are-you-sure.js"></script> <script> $(function() { $('#myForm').areYouSure( { message: 'It looks like you have been editing something. ' + 'If you leave before saving, your changes will be lost.' } ); }); </script> 

自定义消息不受支持

请注意, 自2011年以来 ,Firefox 4在此对话框中不支持自定义消息。 截至上个月,Chrome 51正在推出,其中自定义消息也被删除 。

本网站的其他地方也有一些替代scheme,但我认为这样的对话是非常清楚的:

你想离开这个网站吗?

您所做的更改可能无法保存。

留下

检查JavaScript onbeforeunload事件 。 这是由微软推出的非标准的JavaScript,但是它在大多数浏览器中都能正常工作,而且他们的onbeforeunload文档中有更多的信息和例子。

通过jquery

 $('#form').data('serialize',$('#form').serialize()); // On load save form current state $(window).bind('beforeunload', function(e){ if($('#form').serialize()!=$('#form').data('serialize'))return true; else e=null; // ie; if form state change show warning box, else don't show it. }); 

您可以通过Google JQuery Form Serialize函数,这将收集所有表单input并将其保存在数组中。 我想这个解释就足够了:)

根据以前的答案,并从堆栈溢出的各个地方拼凑在一起,这是我提出的解决scheme,当你真的想要提交你的更改处理的情况:

 window.thisPage = window.thisPage || {}; window.thisPage.isDirty = false; window.thisPage.closeEditorWarning = function (event) { if (window.thisPage.isDirty) return 'It looks like you have been editing something' + ' - if you leave before saving, then your changes will be lost.' else return undefined; }; $("form").on('keyup', 'textarea', // You can use input[type=text] here as well. function () { window.thisPage.isDirty = true; }); $("form").submit(function () { QC.thisPage.isDirty = false; }); window.onbeforeunload = window.thisPage.closeEditorWarning; 

值得注意的是,IE11似乎要求closeEditorWarning函数返回undefined因为它不显示警报。

以下代码很好。 你需要通过id属性来达到表单元素的input变化:

 var somethingChanged=false; $('#managerForm input').change(function() { somethingChanged = true; }); $(window).bind('beforeunload', function(e){ if(somethingChanged) return "You made some changes and it's not saved?"; else e=null; // ie; if form state change show warning box, else don't show it. }); }); 

以下一行已经为我工作。

 window.onbeforeunload = s => modified ? "" : null; 

只要根据应用程序的状态将modified设置为truefalse即可

 var unsaved = false; $(":input").change(function () { unsaved = true; }); function unloadPage() { if (unsaved) { alert("You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?"); } } window.onbeforeunload = unloadPage; 

添加到@ codecaster的想法,你可以添加到每一个页面的forms(在我的情况下,我用全局的方式,所以只有在窗体上会有这个警告)改变他的function

 if ( formSubmitting || document.getElementsByTagName('form').length == 0) 

也可以把表格提交包括login和取消button的链接,所以当人们按下取消或提交表单时也不会触发警告也在每个页面witouthforms…

 <a class="btn btn-danger btn-md" href="back/url" onclick="setFormSubmitting()">Cancel</a> 

你可以在这里查看一下详细的解释: http : //techinvestigations.redexp.in/comparison-of-form-values-on-load-and-before-close/ comparison-form-values-on-load-and -beforeclosures

主要代码:

 function formCompare(defaultValues, valuesOnClose) { // Create arrays of property names var aPropsFormLoad = Object.keys(defaultValues); var aPropsFormClose = Object.keys(valuesOnClose); // If number of properties is different, // objects are not equivalent if (aPropsFormLoad.length != aPropsFormClose.length) { return false; } for (var i = 0; i < aPropsFormLoad.length; i++) { var propName = aPropsFormLoad[i]; // If values of same property are not equal, // objects are not equivalent if (defaultValues[aPropsFormLoad]+"" !== valuesOnClose[aPropsFormLoad]+"") { return false; } } // If we made it this far, objects // are considered equivalent return true; } //add polyfill for older browsers, as explained on the link above //use the block below on load for(i=0; i < document.forms[0].elements.length; i++){ console.log("The field name is: " + document.forms[0].elements[i].name + " and it's value is: " + document.forms[0].elements[i].value ); aPropsFormLoad[i] = document.forms[0].elements[i].value; } //create a similar array on window unload event. //and call the utility function if (!formCompare(aPropsOnLoad, aPropsOnClose)) { //perform action: //ask user for confirmation or //display message about changes made } 

首先,大多数浏览器默认都有这个function。 为什么你需要这个呢? 为什么不保持表单同步? 我的意思是,保存它的任何变化,而不用等待任何提交来自用户。 像谷歌联系人一样。 当然,如果只有forms上的所有领域都是强制性的。 用户不喜欢什么时候强迫他们填充某些东西,而没有机会去思考他们是否需要它。 🙂