我的应用程序中有一些带有表单的页面。
我如何才能保护表单,以便在有人离开或关闭浏览器选项卡时,应提示他们确认他们确实希望将表单保留为未保存的数据?
我的应用程序中有一些带有表单的页面。
我如何才能保护表单,以便在有人离开或关闭浏览器选项卡时,应提示他们确认他们确实希望将表单保留为未保存的数据?
您可以通过处理beforeunload
事件并返回一个非空字符串来做到这一点:
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 和表单序列化,但是这种方法有一些缺陷。首先,您必须更改代码以适用于任何形式($("form").each()
可以),但最大的问题是 jQueryserialize()
仅适用于命名的非禁用元素,因此更改任何禁用或未命名的元素都不会触发脏标志。对此有一些解决方法,例如将控件设为只读,而不是启用、序列化然后再次禁用控件。
所以事件似乎是要走的路。您可以尝试听按键。这个事件有几个问题:
该change
事件也不会在从 JavaScript 代码设置的值上触发,因此也不适用于虚拟输入。
将input
事件绑定到页面上的所有input
s(以及textarea
s 和select
s)在旧浏览器上不起作用,并且与上面提到的所有事件处理解决方案一样,不支持撤消。当用户更改文本框然后撤消该操作,或选中和取消选中复选框时,表单仍被视为脏的。
当您想要实现更多行为时,例如忽略某些元素,您将有更多工作要做。
因此,在您考虑实施这些解决方案和所有必需的变通方法之前,请意识到您正在重新发明轮子,并且您很容易遇到其他人已经为您解决的问题。
如果您的应用程序已经使用 jQuery,那么您最好使用经过测试、维护的代码,而不是滚动自己的代码,并使用第三方库来完成所有这些。
jquery.dirty(由@troseman 在评论中建议)提供了正确检测表单是否已更改的功能,并防止用户在显示提示时离开页面。它还具有其他有用的功能,例如重置表单,以及将表单的当前状态设置为“干净”状态。用法示例:
$("#myForm").dirty({preventLeaving: true});
一个较旧的、目前已被废弃的项目,是jQuery 的你确定吗?plugin,它也很好用;查看他们的演示页面。用法示例:
<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不支持此对话框中的自定义消息。截至 2016 年 4 月,Chrome 51 正在推出,其中自定义消息也被删除。
本网站的其他地方存在一些替代方案,但我认为这样的对话已经足够清楚了:
你想离开这个网站吗?
您所做的更改可能无法保存。
Leave Stay
查看 JavaScript onbeforeunload 事件。它是 Microsoft 引入的非标准 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; // i.e; if form state change show warning box, else don't show it.
});
您可以使用 Google JQuery Form Serialize 函数,这将收集所有表单输入并将其保存在数组中。我想这个解释就足够了:)
无需配置即可自动检测所有输入修改的通用解决方案,包括 contenteditable 元素:
"use strict";
(() => {
const modified_inputs = new Set;
const defaultValue = "defaultValue";
// store default values
addEventListener("beforeinput", (evt) => {
const target = evt.target;
if (!(defaultValue in target || defaultValue in target.dataset)) {
target.dataset[defaultValue] = ("" + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener("input", (evt) => {
const target = evt.target;
let original;
if (defaultValue in target) {
original = target[defaultValue];
} else {
original = target.dataset[defaultValue];
}
if (original !== ("" + (target.value || target.textContent)).trim()) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
});
// clear modified inputs upon form submission
addEventListener("submit", (evt) => {
modified_inputs.clear();
// to prevent the warning from happening, it is advisable
// that you clear your form controls back to their default
// state with evt.target.reset() or form.reset() after submission
});
// warn before closing if any inputs are modified
addEventListener("beforeunload", (evt) => {
if (modified_inputs.size) {
const unsaved_changes_warning = "Changes you made may not be saved.";
evt.returnValue = unsaved_changes_warning;
return unsaved_changes_warning;
}
});
})();
建立在Wasim A.使用序列化的绝妙想法之上。问题是在提交表单时也会显示警告。这已在此处修复。
var isSubmitting = false
$(document).ready(function () {
$('form').submit(function(){
isSubmitting = true
})
$('form').data('initial-state', $('form').serialize());
$(window).on('beforeunload', function() {
if (!isSubmitting && $('form').serialize() != $('form').data('initial-state')){
return 'You have unsaved changes which will not be saved.'
}
});
})
它已经在 Chrome 和 IE 11 中进行了测试。