在离开未保存的更改的网页之前警告用户
我的应用程序中有一些带有表单的页面。
我如何确保表单的安全,如果有人浏览或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
(以及textarea
和select
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
设置为true或false即可 。
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上的所有领域都是强制性的。 用户不喜欢什么时候强迫他们填充某些东西,而没有机会去思考他们是否需要它。 🙂