신청서에 양식이있는 페이지가 있습니다.
다른 사람이 브라우저 탭을 탐색하거나 닫을 경우 저장되지 않은 데이터로 양식을 실제로 남기고 싶은지 묻는 메시지가 표시되도록 양식을 어떻게 보호 할 수 있습니까?
신청서에 양식이있는 페이지가 있습니다.
다른 사람이 브라우저 탭을 탐색하거나 닫을 경우 저장되지 않은 데이터로 양식을 실제로 남기고 싶은지 묻는 메시지가 표시되도록 양식을 어떻게 보호 할 수 있습니까?
답변:
이벤트 를 처리하고 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.
});
이 방법의 문제점 은 양식 을 제출하면 unload 이벤트도 발생한다는 것 입니다. 이것은 양식을 제출하는 플래그를 추가하여 쉽게 수정됩니다.
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
이벤트를 "dirty"플래그와 함께 사용하여 실제로 관련이있는 경우에만 프롬프트를 트리거하는 것입니다.
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 serialization을 사용할 수 있지만이 방법에는 몇 가지 결함이 있습니다. 먼저 모든 형식에서 작동하도록 코드를 변경 $("form").each()
해야하지만 가장 큰 문제는 jQuery가 serialize()
명명되지 않은 비활성화 된 요소에서만 작동하므로 비활성화되거나 명명되지 않은 요소를 변경하면 더티 플래그가 트리거되지 않는다는 것입니다. 이에 대한 해결 방법이 있습니다컨트롤을 활성화, 직렬화 및 비활성화하는 대신 컨트롤을 읽기 전용으로 설정 등의 .
따라서 이벤트는 갈 길로 보입니다. 키 누르기를들을 수 있습니다 . 이 이벤트에는 몇 가지 문제가 있습니다.
이 change
이벤트 는 JavaScript 코드에서 설정된 값에서 트리거되지 않으므로 가상 입력에서도 작동하지 않습니다.
input
이벤트를 페이지의 모든 input
(및 textarea
s 및 select
s) 에 바인딩하면 이전 브라우저에서 작동 하지 않으며 위에서 언급 한 모든 이벤트 처리 솔루션과 마찬가지로 실행 취소를 지원하지 않습니다. 사용자가 텍스트 상자를 변경 한 다음 취소하거나 확인란을 선택 및 선택 취소하면 양식이 여전히 더티로 간주됩니다.
특정 요소를 무시하는 등 더 많은 동작을 구현하려면 더 많은 작업을 수행해야합니다.
따라서 이러한 솔루션과 필요한 모든 해결 방법을 구현하기 전에 휠을 재발 명하고 다른 사람들이 이미 해결 한 문제가 발생하기 쉽다는 것을 알아야합니다.
응용 프로그램에서 이미 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>
양해를 수행 파이어 폭스 4는 이 대화 상자에서 지원 사용자 정의 메시지하지 않았다. 2016 년 4 월 기준 으로 맞춤 메시지도 제거 되는 Chrome 51이 출시 되고 있습니다. .
이 사이트의 다른 곳에서 일부 대안이 존재하지만 이와 같은 대화가 충분히 명확하다고 생각합니다.
이 사이트를 떠나시겠습니까?
변경 사항이 저장되지 않을 수 있습니다.
Leave Stay
JavaScript onbeforeunload 이벤트를 확인하십시오 . Microsoft에서 도입 한 비표준 JavaScript이지만 대부분의 브라우저에서 작동하며 해당 설명서 에는 더 많은 정보와 예제가 있습니다.
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
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/ 비교 -의 - 형태 - 값 - 온 -로드 및 -닫기 전에
주요 코드 :
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
}
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 (2019 년 2 월 7 일 현재)에서도 작동합니다.
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.";
}
};
내가 원치 않는 경고 메시지가 양식을 제출할 때 잘 작동하지만-다른 문제를 가지고, 내가 onsubmit 그게 전부 이전입니다 onbeforeunload 화재는 우리가 같은 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 주소록처럼. 물론 양식의 모든 필드 만 필수 인 경우. 사용자는 필요할 때 생각하지 않고 무언가를 채우려 고 할 때 싫어합니다. :)
save it on any change without waiting any submitting from user
항상 이렇게하고 싶지는 않습니다. 때때로 사용자는 많은 변경을 한 다음 저장하고 싶은지 검토하고 확인하려고합니다.