[javascript] 저장되지 않은 변경 사항으로 웹 페이지를 떠나기 전에 사용자에게 경고

신청서에 양식이있는 페이지가 있습니다.

다른 사람이 브라우저 탭을 탐색하거나 닫을 경우 저장되지 않은 데이터로 양식을 실제로 남기고 싶은지 묻는 메시지가 표시되도록 양식을 어떻게 보호 할 수 있습니까?



답변

짧고 오답 :

이벤트처리하고 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()명명되지 않은 비활성화 된 요소에서만 작동하므로 비활성화되거나 명명되지 않은 요소를 변경하면 더티 플래그가 트리거되지 않는다는 것입니다. 이에 대한 해결 방법이 있습니다컨트롤을 활성화, 직렬화 및 비활성화하는 대신 컨트롤을 읽기 전용으로 설정 등의 .

따라서 이벤트는 갈 길로 보입니다. 키 누르기를들을 수 있습니다 . 이 이벤트에는 몇 가지 문제가 있습니다.

  • 확인란, 라디오 버튼 또는 마우스 입력을 통해 변경되는 기타 요소에서는 트리거되지 않습니다.
  • 키와 관련이없는 키 누르기를 트리거합니다 Ctrl.
  • JavaScript 코드를 통해 설정된 값에서 트리거되지 않습니다.
  • 상황에 맞는 메뉴를 통해 텍스트를 자르거나 붙여 넣을 때 트리거되지 않습니다.
  • JavaScript를 통해 숨겨진 입력에 값을 저장하는 날짜 선택기 또는 확인란 / 라디오 버튼 아름답 기와 같은 가상 입력에는 작동하지 않습니다.

change이벤트JavaScript 코드에서 설정된 값에서 트리거되지 않으므로 가상 입력에서도 작동하지 않습니다.

input이벤트를 페이지의 모든 input(및 textareas 및 selects)바인딩하면 이전 브라우저에서 작동 하지 않으며 위에서 언급 한 모든 이벤트 처리 솔루션과 마찬가지로 실행 취소를 지원하지 않습니다. 사용자가 텍스트 상자를 변경 한 다음 취소하거나 확인란을 선택 및 선택 취소하면 양식이 여전히 더티로 간주됩니다.

특정 요소를 무시하는 등 더 많은 동작을 구현하려면 더 많은 작업을 수행해야합니다.

바퀴를 재발 명하지 마십시오 :

따라서 이러한 솔루션과 필요한 모든 해결 방법을 구현하기 전에 휠을 재발 명하고 다른 사람들이 이미 해결 한 문제가 발생하기 쉽다는 것을 알아야합니다.

응용 프로그램에서 이미 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합니다.


답변

다음 한 줄짜리가 나를 위해 일했습니다.

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

그냥 설정 modified 또는 거짓이 응용 프로그램의 상태에 따라.