ฉันมีบางหน้าพร้อมแบบฟอร์มในใบสมัครของฉัน
ฉันจะรักษาความปลอดภัยให้กับฟอร์มได้อย่างไรถ้ามีคนนำทางไปหรือปิดแท็บเบราว์เซอร์พวกเขาควรได้รับแจ้งให้ยืนยันว่าพวกเขาต้องการออกจากแบบฟอร์มด้วยข้อมูลที่ไม่ได้บันทึกจริง ๆ หรือไม่
ฉันมีบางหน้าพร้อมแบบฟอร์มในใบสมัครของฉัน
ฉันจะรักษาความปลอดภัยให้กับฟอร์มได้อย่างไรถ้ามีคนนำทางไปหรือปิดแท็บเบราว์เซอร์พวกเขาควรได้รับแจ้งให้ยืนยันว่าพวกเขาต้องการออกจากแบบฟอร์มด้วยข้อมูลที่ไม่ได้บันทึกจริง ๆ หรือไม่
คำตอบ:
คุณสามารถทำได้โดยจัดการกับbeforeunload
เหตุการณ์และส่งคืนสตริงที่ไม่ใช่ค่า null :
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.
});
ปัญหาด้วยวิธีนี้คือการส่งแบบฟอร์มนี้ยังยิงขน event สิ่งนี้ได้รับการแก้ไขอย่างง่ายดายโดยการเพิ่มการตั้งค่าสถานะที่คุณส่งแบบฟอร์ม:
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.
});
};
จากนั้นเรียกตัวตั้งค่าเมื่อส่ง:
<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()
จะทำ) แต่ปัญหาที่ยิ่งใหญ่ที่สุดคือ jQuery นั้นserialize()
จะทำงานกับองค์ประกอบที่มีชื่อที่ไม่ได้ปิดการใช้งานเท่านั้นดังนั้นการเปลี่ยนองค์ประกอบที่ถูกปิดใช้งานหรือไม่มีชื่อใด ๆ มีวิธีแก้ปัญหาสำหรับสิ่งนั้นนั้นเช่นการควบคุมแบบอ่านอย่างเดียวแทนการเปิดใช้งานการทำให้เป็นอนุกรมแล้วปิดใช้งานการควบคุมอีกครั้ง
ดังนั้นเหตุการณ์ดูเหมือนจะเป็นไป คุณสามารถลองฟังสำหรับ keypresses เหตุการณ์นี้มีปัญหาเล็กน้อย:
change
เหตุการณ์ยังไม่ได้เรียกค่าตั้งจากโค้ด JavaScriptจึงยังจะไม่ทำงานสำหรับปัจจัยการผลิตเสมือน
การผูกinput
กิจกรรมกับinput
s (และtextarea
s ทั้งหมดselect
)บนหน้าของคุณจะไม่ทำงานบนเบราว์เซอร์รุ่นเก่าและเช่นเดียวกับโซลูชันการจัดการกิจกรรมที่กล่าวถึงข้างต้นไม่สนับสนุนการเลิกทำ เมื่อผู้ใช้เปลี่ยนกล่องข้อความแล้วยกเลิกการทำเช่นนั้นหรือตรวจสอบและยกเลิกการเลือกช่องทำเครื่องหมายแบบฟอร์มยังถือว่าสกปรก
และเมื่อคุณต้องการที่จะใช้พฤติกรรมมากขึ้นเช่นการไม่สนใจองค์ประกอบบางอย่างคุณจะต้องทำงานมากขึ้น
ดังนั้นก่อนที่คุณจะคิดเกี่ยวกับการใช้โซลูชันเหล่านั้นและวิธีการแก้ไขที่จำเป็นทั้งหมดให้ตระหนักว่าคุณได้คิดค้นนวัตกรรมใหม่ ๆ และคุณมีแนวโน้มที่จะประสบปัญหาที่ผู้อื่นได้แก้ไขให้คุณแล้ว
หากแอปพลิเคชันของคุณใช้ jQuery อยู่แล้วคุณอาจใช้ทดสอบบำรุงรักษารหัสแทนการม้วนของคุณเองและใช้ไลบรารี่ส่วนที่สามสำหรับทั้งหมดนี้ 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>
โปรดทราบว่าFirefox 4ไม่รองรับข้อความที่กำหนดเองในกล่องโต้ตอบนี้ ตั้งแต่เดือนเมษายนปี 2016 Chrome 51 กำลังเปิดตัวซึ่งข้อความที่กำหนดเองจะถูกลบออกเช่นกัน
มีบางตัวเลือกอื่นในเว็บไซต์นี้ แต่ฉันคิดว่ากล่องโต้ตอบแบบนี้ชัดเจนพอ:
คุณต้องการออกจากเว็บไซต์นี้หรือไม่?
การเปลี่ยนแปลงที่คุณทำอาจไม่ถูกบันทึก
Leave Stay
ตรวจสอบ 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 สิ่งนี้จะรวบรวมอินพุตแบบฟอร์มทั้งหมดและบันทึกลงในอาร์เรย์ ฉันคิดว่าคำอธิบายนี้เพียงพอแล้ว :)
โซลูชันสากลที่ไม่ต้องมีการกำหนดค่าที่ตรวจจับการดัดแปลงอินพุตทั้งหมดโดยอัตโนมัติรวมถึงองค์ประกอบที่มีเนื้อหา:
"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", () => {
modified_inputs.clear();
// to prevent the warning from happening, it is advisable
// that you clear your form controls back to their default
// state 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
จากคำตอบก่อนหน้านี้และปูด้วยกันจากที่ต่าง ๆ ในสแต็คล้นนี่คือวิธีแก้ไขที่ฉันจัดการกับกรณีเมื่อคุณต้องการส่งการเปลี่ยนแปลงของคุณ:
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
เพื่อที่จะไม่แสดงการแจ้งเตือน
QC.thisPage.isDirty = false;
จะเป็นwindow.thisPage.isDirty = false;
? ด้วยวิธีนี้มันจะตรวจสอบว่าคุณกำลังส่งแบบฟอร์มและไม่แสดงคำเตือน ดูเหมือนว่าจะทำงานสำหรับการทดสอบของฉัน นอกจากนี้รูปแบบที่สุดมีมากกว่าinput
textarea
ฉันใช้สิ่งต่อไปนี้ซึ่งใช้งานได้ดี:$("form").on('keyup', 'textarea,input,select', function () {
หนึ่งซับต่อไปนี้ได้ผลสำหรับฉัน
window.onbeforeunload = s => modified ? "" : null;
เพียงแค่ตั้งค่าmodified
ที่จะเป็นจริงหรือเท็จขึ้นอยู่กับสถานะของใบสมัครของคุณ
undefined
แทนที่จะnull
เป็น IE จะพิมพ์ 'null' หากmodified
เป็นเท็จ
รหัสต่อไปนี้ใช้งานได้ดี คุณต้องเข้าถึงการเปลี่ยนแปลงการป้อนข้อมูลองค์ประกอบองค์ประกอบผ่านแอตทริบิวต์ id:
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; // i.e; if form state change show warning box, else don't show it.
});
});
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;
คุณสามารถใช้ serialize () เพื่อสร้างสตริงข้อความที่เข้ารหัส URL โดยการทำให้เป็นค่าแบบฟอร์มและตรวจสอบว่าแบบฟอร์มมีการเปลี่ยนแปลงก่อนที่จะยกเลิกการโหลด
$(document).ready(function(){
var form = $('#some-form'),
original = form.serialize()
form.submit(function(){
window.onbeforeunload = null
})
window.onbeforeunload = function(){
if (form.serialize() != original)
return 'Are you sure you want to leave?'
}
})
อ้างอิงลิงค์นี้https://coderwall.com/p/gny70a/alert-when-leaving-page-with-unsaved-form เขียนโดย Vladimir Sidorenko
serialize()
แล้วและแน่นอนว่ามันมีข้อเสีย
การเพิ่มความคิดของ @codecaster คุณสามารถเพิ่มสิ่งนี้ลงในทุก ๆ หน้าด้วยแบบฟอร์ม (ในกรณีของฉันฉันใช้มันในแบบสากลดังนั้นในแบบฟอร์มที่จะมีคำเตือนนี้เท่านั้น) เปลี่ยนหน้าที่ของเขาเป็น
if ( formSubmitting || document.getElementsByTagName('form').length == 0)
นอกจากนี้ยังใส่ในแบบฟอร์มส่งรวมถึงการเข้าสู่ระบบและในการยกเลิกการเชื่อมโยงปุ่มดังนั้นเมื่อคนกดยกเลิกหรือส่งแบบฟอร์มจะไม่ก่อให้เกิดการเตือนในทุกหน้าด้วยฟอร์ม ...
<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/ การเปรียบเทียบรูปแบบของค่า -on-load-and -before อย่างใกล้ชิด
รหัสหลัก:
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
}
คำตอบสั้น ๆ :
let pageModified = true
window.addEventListener("beforeunload",
() => pageModified ? 'Close page without saving data?' : null
)
การแก้ปัญหาโดย Eerik Sven Puudist ...
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.'
}
});
})
... โดยธรรมชาติแล้วฉันทำงานในการตั้งค่าเชิงวัตถุที่ซับซ้อนโดยไม่มีการเปลี่ยนแปลงใด ๆ ที่จำเป็น
การเปลี่ยนแปลงเพียงอย่างเดียวที่ฉันนำมาใช้คือการอ้างถึงรูปแบบที่เป็นรูปธรรม (หนึ่งรูปแบบต่อไฟล์) ที่เรียกว่า "formForm" ('form' -> '#formForm'):
<form ... id="formForm" name="formForm" ...>
ทำได้ดีมากโดยเฉพาะอย่างยิ่งความจริงที่ว่าปุ่มส่งกำลังถูก "เหลือคนเดียว"
นอกจากนี้มันใช้งานได้กับฉันด้วย Firefox เวอร์ชันล่าสุด (จนถึงวันที่ 7 กุมภาพันธ์ 2019)
โซลูชันสากลของ Eli Grey ที่ทดสอบแล้วทำงานได้หลังจากที่ฉันทำให้โค้ดง่ายขึ้นเท่านั้น
'use strict';
(() => {
const modified_inputs = new Set();
const defaultValue = 'defaultValue';
// store default values
addEventListener('beforeinput', evt => {
const target = evt.target;
if (!(defaultValue in target.dataset)) {
target.dataset[defaultValue] = ('' + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener('input', evt => {
const target = evt.target;
let original = target.dataset[defaultValue];
let current = ('' + (target.value || target.textContent)).trim();
if (original !== current) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
});
addEventListener(
'saved',
function(e) {
modified_inputs.clear()
},
false
);
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;
}
});
})();
การดัดแปลงของเขาจะถูกลบการใช้งานtarget[defaultValue]
และการใช้งานเท่านั้นtarget.dataset[defaultValue]
เพื่อเก็บค่าเริ่มต้นจริงเท่านั้น
และฉันได้เพิ่มฟังเหตุการณ์ 'บันทึก' ที่เหตุการณ์ 'บันทึก' จะถูกเรียกด้วยตัวเองในการดำเนินการบันทึกของคุณสำเร็จ
แต่โซลูชัน 'สากล' นี้ใช้ได้กับเบราว์เซอร์เท่านั้นไม่สามารถใช้งานได้ในมุมมองเว็บของแอปตัวอย่างเช่น wechat เบราว์เซอร์
ในการทำให้เบราว์เซอร์ wechat (บางส่วน) ทำงานได้ดีขึ้นอีก:
'use strict';
(() => {
const modified_inputs = new Set();
const defaultValue = 'defaultValue';
// store default values
addEventListener('beforeinput', evt => {
const target = evt.target;
if (!(defaultValue in target.dataset)) {
target.dataset[defaultValue] = ('' + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener('input', evt => {
const target = evt.target;
let original = target.dataset[defaultValue];
let current = ('' + (target.value || target.textContent)).trim();
if (original !== current) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
if(modified_inputs.size){
const event = new Event('needSave')
window.dispatchEvent(event);
}
});
addEventListener(
'saved',
function(e) {
modified_inputs.clear()
},
false
);
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;
}
});
const ua = navigator.userAgent.toLowerCase();
if(/MicroMessenger/i.test(ua)) {
let pushed = false
addEventListener('needSave', evt => {
if(!pushed) {
pushHistory();
window.addEventListener("popstate", function(e) {
if(modified_inputs.size) {
var cfi = confirm('确定要离开当前页面嘛?' + JSON.stringify(e));
if (cfi) {
modified_inputs.clear()
history.go(-1)
}else{
e.preventDefault();
e.stopPropagation();
}
}
}, false);
}
pushed = true
});
}
function pushHistory() {
var state = {
title: document.title,
url: "#flag"
};
window.history.pushState(state, document.title, "#flag");
}
})();
ฉันทำมันแตกต่างกันแบ่งปันที่นี่เพื่อให้ใครบางคนสามารถรับความช่วยเหลือทดสอบกับ Chrome เท่านั้น
ฉันต้องการเตือนผู้ใช้ก่อนที่จะปิดแท็บเฉพาะเมื่อมีการเปลี่ยนแปลงบางอย่าง
<input type="text" name="field" value="" class="onchange" />
var ischanged = false;
$('.onchange').change(function () {
ischanged = true;
});
window.onbeforeunload = function (e) {
if (ischanged) {
return "Make sure to save all changes.";
}
};
ทำงานได้ดี แต่เกิดปัญหาอื่นเมื่อฉันส่งแบบฟอร์มที่ฉันได้รับการเตือนที่ไม่พึงประสงค์ฉันเห็นจำนวนของการแก้ปัญหาในเรื่องนี้เป็นเพราะไฟ onbeforeunload ก่อนครับ onsubmit ทำไมเราไม่สามารถจัดการกับมันในกรณี onsubmit เหมือนonbeforeunload = null
แต่ เหตุการณ์ onclick ของปุ่มส่งเริ่มก่อนเหตุการณ์ทั้งสองนี้ดังนั้นฉันจึงอัปเดตโค้ด
var isChanged = false;
var isSubmit = false;
window.onbeforeunload = function (e) {
if (isChanged && (!isSubmit)) {
return "Make sure to save all changes.";
}
};
$('#submitbutton').click(function () {
isSubmit = true;
});
$('.onchange').change(function () {
isChanged = true;
});
ก่อนอื่นเบราว์เซอร์ส่วนใหญ่มีฟังก์ชั่นนี้ตามค่าเริ่มต้น และทำไมคุณถึงต้องการสิ่งนี้เลย ทำไมไม่ซิงค์ข้อมูลในฟอร์ม ฉันหมายถึงบันทึกไว้ในการเปลี่ยนแปลงใด ๆ โดยไม่ต้องรอการส่งจากผู้ใช้ เช่นเดียวกับ Google Contacts แน่นอนถ้ามีเพียงฟิลด์ทั้งหมดในฟอร์มที่จำเป็น ผู้ใช้ไม่ชอบเมื่อพวกเขาบังคับให้เติมบางอย่างโดยไม่มีโอกาสที่จะหายไปคิดว่าพวกเขาต้องการ :)
save it on any change without waiting any submitting from user
คุณไม่ต้องการทำเช่นนี้เสมอไป บางครั้งผู้ใช้ต้องการเปลี่ยนแปลงหลายอย่างจากนั้นตรวจสอบและยืนยันว่าต้องการบันทึก