Cómo mostrar el mensaje "¿Está seguro de que desea navegar fuera de esta página?" cuando los cambios comprometidos?

267

Aquí en stackoverflow, si comenzó a hacer cambios, entonces intenta navegar fuera de la página, aparece un botón de confirmación de JavaScript y le pregunta: "¿Está seguro de que desea navegar fuera de esta página?" Blee Blah Bloo ...

¿Alguien ha implementado esto antes? ¿Cómo hago un seguimiento de los cambios que se cometieron? Creo que podría hacerlo yo mismo, estoy tratando de aprender las buenas prácticas de ustedes, los expertos.

Intenté lo siguiente pero aún no funciona:

<html>
<body>
    <p>Close the page to trigger the onunload event.</p>
    <script type="text/javascript">
        var changes = false;        
        window.onbeforeunload = function() {
            if (changes)
            {
                var message = "Are you sure you want to navigate away from this page?\n\nYou have started writing or editing a post.\n\nPress OK to continue or Cancel to stay on the current page.";
                if (confirm(message)) return true;
                else return false;
            }
        }
    </script>

    <input type='text' onchange='changes=true;'> </input>
</body>
</html>

¿Alguien puede publicar un ejemplo?

Shimmy Weitzhandler
fuente
3
Para que su ejemplo funcione, cambie la función a: myFunction () {window.onbeforeunload = "message"; } luego cambie la entrada: <input type = 'text' onchange = 'myFunction ();'> </input>
Keith el
Relacionado: stackoverflow.com/q/821011/435605
AlikElzin-kilaka

Respuestas:

367

Actualización (2017)

Los navegadores modernos ahora consideran que mostrar un mensaje personalizado es un peligro para la seguridad y, por lo tanto, se ha eliminado de todos ellos. Los navegadores ahora solo muestran mensajes genéricos. Como ya no tenemos que preocuparnos por configurar el mensaje, es tan simple como:

// Enable navigation prompt
window.onbeforeunload = function() {
    return true;
};
// Remove navigation prompt
window.onbeforeunload = null;

Lea a continuación para obtener soporte de navegador heredado.

Actualización (2013)

La respuesta original es adecuada para IE6-8 y FX1-3.5 (que es a lo que estábamos apuntando en 2009 cuando se escribió), pero está bastante desactualizada ahora y no funcionará en la mayoría de los navegadores actuales. a continuación para referencia.

El window.onbeforeunloadno es tratado consistentemente por todos los navegadores. Debería ser una referencia de función y no una cadena (como decía la respuesta original), pero eso funcionará en navegadores más antiguos porque la verificación para la mayoría de ellos parece ser si hay algo asignado onbeforeunload(incluida una función que devuelve null).

Establece window.onbeforeunloaduna referencia de función, pero en los navegadores más antiguos debe establecer returnValueel evento en lugar de simplemente devolver una cadena:

var confirmOnPageExit = function (e) 
{
    // If we haven't been passed the event get the window.event
    e = e || window.event;

    var message = 'Any text will block the navigation and display a prompt';

    // For IE6-8 and Firefox prior to version 4
    if (e) 
    {
        e.returnValue = message;
    }

    // For Chrome, Safari, IE8+ and Opera 12+
    return message;
};

No puede confirmOnPageExithacer que verifique y devuelva nulo si desea que el usuario continúe sin el mensaje. Aún necesita eliminar el evento para encenderlo y apagarlo de manera confiable:

// Turn it on - assign the function that returns the string
window.onbeforeunload = confirmOnPageExit;

// Turn it off - remove the function entirely
window.onbeforeunload = null;

Respuesta original (trabajada en 2009)

Encenderlo:

window.onbeforeunload = "Are you sure you want to leave?";

Para apagarlo:

window.onbeforeunload = null;

Tenga en cuenta que este no es un evento normal, no puede unirse a él de la manera estándar.

Para verificar los valores? Eso depende de su marco de validación.

En jQuery esto podría ser algo como (ejemplo muy básico):

$('input').change(function() {
    if( $(this).val() != "" )
        window.onbeforeunload = "Are you sure you want to leave?";
});
Keith
fuente
44
Eso sería algo así como: $ ('input: text'). Change (function () {window.onbeforeunload = $ ('input: text [value! = ""]'). Length> 0? "Warning": null ;});
Keith el
1
Para una verificación simple, o puede agregar una validación más compleja en cada cambio
Keith el
1
Vale la pena señalar que el método 'returnValue' es el único método especificado en el estándar, por lo que no es solo para IE6-8, es para todos los navegadores que cumplen con los estándares (en este caso, sin incluir Chrome, Safari y Opera).
rmcclellan
3
Para detener la alerta en el envío del formulario, solía $("#submit_button").click(function() { window.onbeforeunload = null; });. Originalmente usé el evento onclick del botón, pero además de no ser tan bueno, tampoco funcionó con IE8.
Andy Beverley
1
@ AlikElzin-kilaka no puedes. Si desea cambiar el texto emergente, debe crear su propia ventana emergente personalizada, pero eso no puede bloquear el window.onbeforeunloadevento.
Keith
38

El onbeforeunloadMicrosoft-ism es lo más parecido que tenemos a una solución estándar, pero tenga en cuenta que el soporte del navegador es desigual; por ejemplo, para Opera solo funciona en la versión 12 y posteriores (aún en versión beta a partir de este escrito).

Además, para obtener la máxima compatibilidad , debe hacer más que simplemente devolver una cadena, como se explica en la Red de desarrolladores de Mozilla .

Ejemplo: defina las siguientes dos funciones para habilitar / deshabilitar la solicitud de navegación (consulte el ejemplo de MDN):

function enableBeforeUnload() {
    window.onbeforeunload = function (e) {
        return "Discard changes?";
    };
}
function disableBeforeUnload() {
    window.onbeforeunload = null;
}

Luego defina una forma como esta:

<form method="POST" action="" onsubmit="disableBeforeUnload();">
    <textarea name="text"
              onchange="enableBeforeUnload();"
              onkeyup="enableBeforeUnload();">
    </textarea>
    <button type="submit">Save</button>
</form>

De esta manera, el usuario solo será advertido sobre la posibilidad de navegar si ha cambiado el área de texto, y no se le preguntará cuando envíe el formulario.

Søren Løvborg
fuente
1
Basado en el sitio de Mozill, los navegadores de escritorio más recientes ahora lo admiten: developer.mozilla.org/en/DOM/window.onbeforeunload
Hengjie
Microsoft-ism es un gran término.
Luke Taylor
18

Con JQuery, esto es bastante fácil de hacer. Ya que puedes unirte a conjuntos.

NO es suficiente para hacer onbeforeunload, solo desea activar la navegación si alguien comienza a editar cosas.

Sam Azafrán
fuente
2
Parece que no puedo llegar a las publicaciones de blog de @jonstjohn. ¿Quizás sea un amigo y nos señale en la dirección correcta? : D
FLGMwt
14
=> 500 Error interno. Es por eso que los enlaces están en desuso en SO. Voto negativo hasta que se arregle.
Loïc
Esta página web no está disponible
Mateusz
2
Si bien este enlace puede responder la pregunta, es mejor incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia.
bwest
2
El enlace original de Jon St John estaba roto, así que lo actualicé a la versión de Wayback Machine . El contenido del enlace se puede encontrar copiado en muchos otros sitios, pero supongo que era mejor "preservar" el que Sam agregó
Alvaro Montoro
14

jquerys 'beforeunload' funcionó muy bien para mí

$(window).bind('beforeunload', function(){
    if( $('input').val() !== '' ){
        return "It looks like you have input you haven't submitted."
    }
});
Devon Peticolas
fuente
Bind ha quedado obsoleto y se puede ver una nueva versión de código similar a esta en esta respuesta: stackoverflow.com/a/1889450/908677
Elijah Lofgren el
12

Para las personas nuevas que buscan una solución simple, simplemente pruebe Areyousure.js

Lawphotog
fuente
11

Esta es una manera fácil de presentar el mensaje si se ingresan datos en el formulario, y no mostrar el mensaje si se envía el formulario:

$(function () {
    $("input, textarea, select").on("input change", function() {
        window.onbeforeunload = window.onbeforeunload || function (e) {
            return "You have unsaved changes.  Do you want to leave this page and lose your changes?";
        };
    });
    $("form").on("submit", function() {
        window.onbeforeunload = null;
    });
})
Carl G
fuente
8

Para ampliar en la respuesta ya sorprendente de Keith :

Mensajes de advertencia personalizados

Para permitir mensajes de advertencia personalizados, puede ajustarlo en una función como esta:

function preventNavigation(message) {
    var confirmOnPageExit = function (e) {
        // If we haven't been passed the event get the window.event
        e = e || window.event;

        // For IE6-8 and Firefox prior to version 4
        if (e)
        {
            e.returnValue = message;
        }

        // For Chrome, Safari, IE8+ and Opera 12+
        return message;
    };
    window.onbeforeunload = confirmOnPageExit;
}

Luego simplemente llame a esa función con su mensaje personalizado:

preventNavigation("Baby, please don't go!!!");

Habilitar la navegación nuevamente

Para volver a habilitar la navegación, todo lo que necesita hacer es configurar window.onbeforeunloada null. Aquí está, envuelto en una pequeña y clara función que se puede llamar en cualquier lugar:

function enableNavigation() {
    window.onbeforeunload = null;
}

Usando jQuery para vincular esto para formar elementos

Si usa jQuery, esto puede vincularse fácilmente a todos los elementos de un formulario como este:

$("#yourForm :input").change(function() {
    preventNavigation("You have not saved the form. Any \
        changes will be lost if you leave this page.");
});

Luego, para permitir que se envíe el formulario:

$("#yourForm").on("submit", function(event) {
    enableNavigation();
});

Formas modificadas dinámicamente:

preventNavigation()y enableNavigation()puede vincularse a cualquier otra función según sea necesario, como modificar dinámicamente un formulario o hacer clic en un botón que envía una solicitud AJAX. Lo hice agregando un elemento de entrada oculto al formulario:

<input id="dummy_input" type="hidden" />

Luego, cada vez que quiero evitar que el usuario navegue, active el cambio en esa entrada para asegurarme de que preventNavigation()se ejecute:

function somethingThatModifiesAFormDynamically() {

    // Do something that modifies a form

    // ...
    $("#dummy_input").trigger("change");
    // ...
}
Miguel
fuente
3

Aquí intenta esto, funciona al 100%

<html>
<body>
<script>
var warning = true;
window.onbeforeunload = function() {  
  if (warning) {  
    return "You have made changes on this page that you have not yet confirmed. If you navigate away from this page you will lose your unsaved changes";  
    }  
}

$('form').submit(function() {
   window.onbeforeunload = null;
});
</script>
</body>
</html>
Braydon
fuente
3

El estándar establece que la solicitud se puede controlar cancelando el evento beforeunload o estableciendo el valor de retorno en un valor no nulo . También establece que los autores deben usar Event.preventDefault () en lugar de returnValue, y el mensaje que se muestra al usuario no es personalizable .

A partir de 69.0.3497.92, Chrome no ha cumplido con el estándar. Sin embargo, hay un informe de error archivado y una revisión en curso. Chrome requiere que returnValue se establezca por referencia al objeto de evento, no por el valor devuelto por el controlador.

Es responsabilidad del autor rastrear si se han realizado cambios; se puede hacer con una variable o asegurando que el evento solo se maneje cuando sea necesario.

window.addEventListener('beforeunload', function (e) {
    // Cancel the event as stated by the standard.
    e.preventDefault();
    // Chrome requires returnValue to be set.
    e.returnValue = '';
});
    
window.location = 'about:blank';

Trevor Karjanis
fuente
2

Cuando el usuario comienza a realizar cambios en el formulario, se establecerá una bandera booleana. Si el usuario intenta salir de la página, verifica esa bandera en el evento window.onunload . Si se establece el indicador, muestra el mensaje devolviéndolo como una cadena. Si devuelve el mensaje como una cadena, aparecerá un cuadro de diálogo de confirmación con su mensaje.

Si está utilizando ajax para confirmar los cambios, puede establecer el indicador falsedespués de que los cambios se hayan confirmado (es decir, en el evento de éxito de ajax).

Kirtan
fuente
1

Puede agregar un onchangeevento en el área de texto (o cualquier otro campo) que establezca una variable en JS. Cuando el usuario intenta cerrar la página (window.onunload), verifica el valor de esa variable y muestra la alerta en consecuencia.

Makram Saleh
fuente
1
No puede hacer esto, alerty confirmestá bloqueado durante window.onbeforeunloady window.onunload(al menos en la versión de Chrome en mi PC, pero probablemente también en todos los navegadores para admitir esos controladores).
Mark Amery
1

Basado en todas las respuestas en este hilo, escribí el siguiente código y funcionó para mí.

Si solo tiene algunas etiquetas de entrada / área de texto que requieren que se verifique un evento de descarga, puede asignar atributos de datos HTML5 como data-onunload="true"

por ej.

<input type="text" data-onunload="true" />
<textarea data-onunload="true"></textarea>

y el Javascript (jQuery) puede verse así:

$(document).ready(function(){
    window.onbeforeunload = function(e) {
        var returnFlag = false;
        $('textarea, input').each(function(){
            if($(this).attr('data-onunload') == 'true' && $(this).val() != '')
                returnFlag = true;
        });

        if(returnFlag)
            return "Sure you want to leave?";   
    };
});
Sagar Gala
fuente
2
Consulte también "Por algunos motivos, los navegadores basados ​​en Webkit no siguen las especificaciones del cuadro de diálogo" en la documentación de MDN antes de la descarga .
Arjan
1

aqui esta mi html

<!DOCTYPE HMTL>
<meta charset="UTF-8">
<html>
<head>
<title>Home</title>
<script type="text/javascript" src="script.js"></script>
</head>

 <body onload="myFunction()">
    <h1 id="belong">
        Welcome To My Home
    </h1>
    <p>
        <a id="replaceME" onclick="myFunction2(event)" href="https://www.ccis.edu">I am a student at Columbia College of Missouri.</a>
    </p>
</body>

Y así es como hice algo similar en JavaScript

var myGlobalNameHolder ="";

function myFunction(){
var myString = prompt("Enter a name", "Name Goes Here");
    myGlobalNameHolder = myString;
    if (myString != null) {
        document.getElementById("replaceME").innerHTML =
        "Hello " + myString + ". Welcome to my site";

        document.getElementById("belong").innerHTML =
        "A place you belong";
    }   
}

// create a function to pass our event too
function myFunction2(event) {   
// variable to make our event short and sweet
var x=window.onbeforeunload;
// logic to make the confirm and alert boxes
if (confirm("Are you sure you want to leave my page?") == true) {
    x = alert("Thank you " + myGlobalNameHolder + " for visiting!");
}
}
Justin Stone
fuente
0

Se puede hacer fácilmente estableciendo un ChangeFlag en verdadero, en el evento onChange de TextArea . Use javascript para mostrar el cuadro de diálogo de confirmación según el valor de ChangeFlag . Deseche el formulario y navegue a la página solicitada si confirmar devuelve verdadero, de lo contrario no haga nada .

simplemente duro
fuente
-1

Hay un parámetro "onunload" para la etiqueta del cuerpo desde allí puede llamar a las funciones de JavaScript. Si devuelve falso, evita navegar lejos.

Stribika
fuente
13
Afortunadamente, esto en realidad no funciona. De lo contrario, odiaría visitar una página que contenga <body onunload="return false;">.
Søren Løvborg