¿Cómo puedo evitar que la tecla de retroceso navegue hacia atrás?


275

En IE puedo hacer esto con el jQuery (terriblemente no estándar, pero que funciona)

if ($.browser.msie)
    $(document).keydown(function(e) { if (e.keyCode == 8) window.event.keyCode = 0;});

¿Pero es posible hacerlo de una manera que funcione en Firefox, o en una forma de navegador cruzado para obtener una bonificación?

Para el registro:

$(document).keydown(function(e) { if (e.keyCode == 8) e.stopPropagation(); });

no hace nada.

$(document).keydown(function(e) { if (e.keyCode == 8) e.preventDefault(); });

resuelve el problema, pero hace que la tecla de retroceso no se pueda usar en la página, lo que es aún peor que el comportamiento original.

EDITAR: La razón por la que hago esto es que no estoy creando una página web simple sino una aplicación grande. Es increíblemente molesto perder 10 minutos de trabajo solo porque presionó la tecla de retroceso en el lugar equivocado. La proporción de prevención de errores frente a usuarios molestos debería estar muy por encima de 1000/1 al evitar que la tecla de retroceso navegue hacia atrás.

Edit2: Soy no tratar de evitar que el historial de navegación, los accidentes solo.

EDITAR3: comentario de @brentonstrines (movido aquí ya que la pregunta es muy popular): Esta es una 'solución' a largo plazo, pero podría brindar su apoyo detrás del error Chromium para cambiar este comportamiento en el kit web


137
Porque la tecla de retroceso está sobrecargada. Es posible que no lo haya notado, pero probablemente lo use todo el tiempo para borrar letras que acaba de escribir en un campo de texto. Algunos de mis clientes han tenido problemas con eso que hace que la página regrese, por lo que esta es información útil. Nadie más que ustedes payasos sabe que se supone que retroceder una página. Eso es algo que nunca supe, y es un comportamiento hostil para un navegador. Creo que todas las páginas deberían deshabilitar ese comportamiento.
Breton

80
¿Por qué la gente piensa que esto es extraño? ¡Usar la tecla de retroceso para la navegación es un atajo realmente tonto! hay tantos campos de texto de los que los usuarios pueden querer eliminar el texto; imagine tener una respuesta SO larga, cambiar a otra ventana para verificar algo, y luego volver y hacer clic mal en el área de edición, presionar la tecla de retroceso para eliminar una palabra y De repente, el navegador retrocede una página y potencialmente ha perdido todo lo que acaba de escribir.
Peter Boughton

57
¿Por qué quiero hacer esto? No estoy creando un sitio web sino una aplicación web. Algunos campos de entrada son de solo lectura, en cuyo caso parecen editables, pero si presiona la tecla de retroceso, abandona la página. La relación de pulsaciones de tecla de retroceso con la intención de prensas de retroceso posterior navegar vs. tratando de borrar algo es probablemente mucho menor que 1 / 1000.
erikkallen

42
La pregunta es cómo hacer esto, no su opinión sobre si es una buena idea o no. Sin conocer los detalles del proyecto, sus opiniones no tienen sentido. Mi cliente ha solicitado específicamente este comportamiento para uno de mis proyectos y una respuesta real en lugar de "¿Por qué querrías hacer eso?" sería de ayuda.
Ninguno

77
Esta es una 'solución' a largo plazo, pero podría brindar su apoyo detrás del error Chromium para cambiar este comportamiento en el kit web
brentonstrine

Respuestas:


335

Este código resuelve el problema, al menos en IE y Firefox (no he probado ningún otro, pero le doy una posibilidad razonable de funcionar si el problema incluso existe en otros navegadores).

// Prevent the backspace key from navigating back.
$(document).unbind('keydown').bind('keydown', function (event) {
    if (event.keyCode === 8) {
        var doPrevent = true;
        var types = ["text", "password", "file", "search", "email", "number", "date", "color", "datetime", "datetime-local", "month", "range", "search", "tel", "time", "url", "week"];
        var d = $(event.srcElement || event.target);
        var disabled = d.prop("readonly") || d.prop("disabled");
        if (!disabled) {
            if (d[0].isContentEditable) {
                doPrevent = false;
            } else if (d.is("input")) {
                var type = d.attr("type");
                if (type) {
                    type = type.toLowerCase();
                }
                if (types.indexOf(type) > -1) {
                    doPrevent = false;
                }
            } else if (d.is("textarea")) {
                doPrevent = false;
            }
        }
        if (doPrevent) {
            event.preventDefault();
            return false;
        }
    }
});

66
Rompe los campos de contraseña.
Hemlock

77
Como dijo Hemlock, verifique d.type.toUpperCase() === 'PASSWORD'también. De lo contrario, se ve bien
stevendesu

17
Como ya estás usando jQueryif( $(d).is( ":input" ) )...
Paul Alexander

23
Es una mierda que esto tenga que ser una lista blanca, en lugar de poder poner en la lista negra la funcionalidad "atrás". Es posible que desee agregar un cheque d.isContentEditableaquí.
iono

3
Creé un proyecto NPM con una versión limpia de la respuesta actualmente aceptada: github.com/slorber/backspace-disabler (también es compatible con contenteditables y no tiene dependencia)
Sebastien Lorber

62

Este código funciona en todos los navegadores y se traga la tecla de retroceso cuando no está en un elemento de formulario, o si el elemento de formulario está desactivado | readOnly. También es eficiente, lo cual es importante cuando se ejecuta en cada tecla ingresada.

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});

1
Por favor, pruebe mi ejemplo, es posible que desee actualizar su código en consecuencia.
Biff MaGriff

10
Prefiero esto sobre la solución de @ erikkallen porque es más limpia. Sin embargo, quería que los botones de envío, los botones de opción y las casillas de verificación también se ignoraran, así que cambié el if () a esto:if(!rx.test(e.target.tagName) || $(e.target).is(':checkbox') || $(e.target).is(':radio') || $(e.target).is(':submit') || e.target.disabled || e.target.readOnly )
Matthew Clark el

@ thetoolman, mira mi comentario sobre la respuesta de erikallen. Esto también debería explicar contentEditable.
sacudida

10
@MaffooClock: puedes ser más conciso con.is(':checkbox,:radio,:submit')
cdmckay

1
@cdmckay: No puedo creer que no lo haya escrito así en primer lugar. Gracias por limpiar eso para todos nosotros :)
Matthew Clark

41

Las otras respuestas aquí han establecido que esto no se puede hacer sin elementos de la lista blanca en los que se permite Retroceso. Esta solución no es ideal porque la lista blanca no es tan sencilla como simplemente las áreas de texto y las entradas de texto / contraseña, pero se encuentra repetidamente incompleta y necesita actualizarse.

Sin embargo, dado que el propósito de suprimir la funcionalidad de retroceso es simplemente para evitar que los usuarios pierdan datos accidentalmente, la solución beforeunload es buena porque la ventana emergente modal es sorprendente: las ventanas emergentes modales son malas cuando se activan como parte de un flujo de trabajo estándar, porque el usuario se acostumbra a descartarlos sin leerlos, y son molestos. En este caso, la ventana emergente modal solo aparecería como una alternativa a una acción rara y sorprendente, y por lo tanto es aceptable.

El problema es que un modal onbeforeunload no debe aparecer cuando el usuario navega fuera de la página (como cuando hace clic en un enlace o envía un formulario), y no queremos comenzar a incluir en la lista blanca o en una lista negra las condiciones específicas de onbeforeunload.

La combinación ideal de compensaciones para una solución generalizada es la siguiente: realizar un seguimiento de si se presiona la tecla de retroceso y solo aparece el modo onbeforeunload si es así. En otras palabras:

function confirmBackspaceNavigations () {
    // http://stackoverflow.com/a/22949859/2407309
    var backspaceIsPressed = false
    $(document).keydown(function(event){
        if (event.which == 8) {
            backspaceIsPressed = true
        }
    })
    $(document).keyup(function(event){
        if (event.which == 8) {
            backspaceIsPressed = false
        }
    })
    $(window).on('beforeunload', function(){
        if (backspaceIsPressed) {
            backspaceIsPressed = false
            return "Are you sure you want to leave this page?"
        }
    })
} // confirmBackspaceNavigations

Esto ha sido probado para funcionar en IE7 +, Firefox, Chrome, Safari y Opera. Simplemente suelte esta función en su global.js y llámela desde cualquier página donde no desee que los usuarios pierdan accidentalmente sus datos.

Tenga en cuenta que un modal onbeforeunload solo se puede activar una vez, por lo que si el usuario presiona la tecla de retroceso nuevamente, el modal no volverá a activarse.

Tenga en cuenta que esto no se activará en eventos de cambio hash, sin embargo, en ese contexto, puede usar otras técnicas para evitar que los usuarios pierdan accidentalmente sus datos.


2
Solo fui a agregar esta misma solución y vi esta publicación en la parte inferior de la página LOL. Una diferencia que tengo es establecer lastUserInputWasBackspace = false antes de la declaración de retorno "¿Está seguro ...", para que no aparezca la ventana emergente si hace clic en el botón Atrás después de ver la ventana emergente (por lo que es coherente con comportamiento influenciado por el retroceso).
David Russell

1
@ user2407309 He eliminado mi comentario (no es una queja) sobre firefox no funciona con su solución. Hubo un problema con mi depurador. Mis disculpas por editar / romper su código. Ahora me doy cuenta de que he sobrepasado mis límites (edición), perdóname. Lo siento mucho y no quise quejarme de su maravillosa solución a este problema. De nuevo, mis disculpas. Este código funciona bien. Creo que esta es la mejor respuesta y te felicito por ello.
Charles Byrne

1
Esta solución funcionó en mi máquina local, pero cuando la moví, el cliente (al menos algunos de ellos) perdió la funcionalidad de la mitad de la aplicación. Supongo que algo lo está rechazando, pero no tengo idea de qué.
Steve

1
@Steve, raro o no, si hay un problema con la función, esa información pertenece aquí. Solo quiero saber si realmente hay un problema.
Vladimir Kornea

1
Buena solución, pero desafortunadamente, si un usuario presiona accidentalmente la tecla de retroceso dos veces, todavía navega hacia atrás. (al menos en firefox)
Remco de Zwart

26

Una solución más elegante / concisa:

$(document).on('keydown',function(e){
  var $target = $(e.target||e.srcElement);
  if(e.keyCode == 8 && !$target.is('input,[contenteditable="true"],textarea'))
  {
    e.preventDefault();
  }
})

1
Esto es mucho más conciso y, por lo que puedo decir, funciona igual de bien. ¿Por qué la respuesta más popular tiene todos esos tipos de entradas y parece más complicada? ¿Es más confiable?
Nearpoint

1
La respuesta más popular fue la primera en responder la pregunta, por lo tanto, los votos altos.
Darwayne

44
cuando los campos de solo lectura están enfocados, eliminar todavía navega de regreso en Chrome
Will D

16

Modificación de la respuesta de erikkallen para abordar diferentes tipos de entrada

Descubrí que un usuario emprendedor podría presionar la tecla de retroceso en una casilla de verificación o un botón de radio en un vano intento de borrarlo y, en su lugar, navegaría hacia atrás y perdería todos sus datos.

Este cambio debería abordar ese problema.

Nueva edición para abordar contenido editable divs

    //Prevents backspace except in the case of textareas and text inputs to prevent user navigation.
    $(document).keydown(function (e) {
        var preventKeyPress;
        if (e.keyCode == 8) {
            var d = e.srcElement || e.target;
            switch (d.tagName.toUpperCase()) {
                case 'TEXTAREA':
                    preventKeyPress = d.readOnly || d.disabled;
                    break;
                case 'INPUT':
                    preventKeyPress = d.readOnly || d.disabled ||
                        (d.attributes["type"] && $.inArray(d.attributes["type"].value.toLowerCase(), ["radio", "checkbox", "submit", "button"]) >= 0);
                    break;
                case 'DIV':
                    preventKeyPress = d.readOnly || d.disabled || !(d.attributes["contentEditable"] && d.attributes["contentEditable"].value == "true");
                    break;
                default:
                    preventKeyPress = true;
                    break;
            }
        }
        else
            preventKeyPress = false;

        if (preventKeyPress)
            e.preventDefault();
    });

Ejemplo
Para probar hacer 2 archivos.

starthere.htm: abre esto primero para que tengas un lugar al que volver

<a href="./test.htm">Navigate to here to test</a>

test.htm: se desplazará hacia atrás cuando se presione la tecla de retroceso mientras la casilla de verificación o el envío tienen el foco (logrado mediante tabulación). Reemplazar con mi código para arreglar.

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">

    $(document).keydown(function(e) {
        var doPrevent;
        if (e.keyCode == 8) {
            var d = e.srcElement || e.target;
            if (d.tagName.toUpperCase() == 'INPUT' || d.tagName.toUpperCase() == 'TEXTAREA') {
                doPrevent = d.readOnly || d.disabled;
            }
            else
                doPrevent = true;
        }
        else
            doPrevent = false;

        if (doPrevent)
            e.preventDefault();
    });
</script>
</head>
<body>
<input type="text" />
<input type="radio" />
<input type="checkbox" />
<input type="submit" />
</body>
</html>

¿Qué navegador viste retroceso presione en radio | casilla de verificación | enviar -> función de retroceso? No he visto a un navegador hacer esto ..
thetoolman

Internet Explorer 8 y Chrome
Biff MaGriff

2
Intenté varias otras soluciones en este hilo, pero esta funcionó bien en todas mis situaciones y tenía el código más limpio y fácil de entender. Gracias.
Ezward

¿Intentaste @Darwayne? Tengo curiosidad por saber por qué ese es tan corto y esto es más complejo, pero ambos parecen funcionar igual para mí
Nearpoint

¿Funciona esto en enlaces? Tengo una aplicación ASP.Net con un botón de imagen para eliminar un elemento. Eso es lo único que no ha funcionado hasta ahora ...
Steve

8

Según los comentarios, parece que desea evitar que las personas pierdan información en los formularios, si presionan la tecla de retroceso para eliminar pero el campo no está enfocado.

En cuyo caso, desea ver el controlador de eventos onunload . Stack Overflow lo usa: si intenta salir de una página cuando comienza a escribir una respuesta, aparece una advertencia.


44
lo siento, fue un comentario grosero. Lo que quiero decir es que el usuario probablemente no quiere ser reprendido por hacer algo que ni siquiera sabían que estaba mal. ¿Por qué no solo comer la llave en silencio con una tecla de encendido? El objetivo no es evitar por completo que el usuario abandone la página, sino evitar este error común. Además, los cuadros de diálogo emergentes no son muy efectivos ni útiles. Los usuarios no los leen. ¿Estás seguro de que quieres salir de la página? ¡Bueno! No, espera, espera, no quería salir de la página ... Uy, demasiado tarde.
Breton

3
OK, entonces tómalo o déjalo. Creo que estás intentando sobre-diseñar un problema que realmente no existe, o al menos no es importante. Y en mi experiencia, solo los usuarios avanzados hacen clic en "Aceptar" en cuadros de diálogo desconocidos sin leerlos correctamente. ;)
DisgruntledGoat

3
¿Eres tú y Breton la misma persona? De todos modos, se disparó un poco en el pie allí: el artículo dice "la respuesta predeterminada es Cancelar", por lo que al ver el cuadro de diálogo sobre salir de la página, presionarán "Cancelar" y, por lo tanto, no saldrán de la página. Aunque debe tenerse en cuenta que las opciones de Chrome en ese cuadro de diálogo son "Salir de esta página" y "Permanecer en esta página", que son muy claras.
DisgruntledGoat

1
No, él no soy yo, pero me he encontrado con ese enlace antes. Creo que los comentarios son divertidos. "¿Qué? ¿La gente ignora los cuadros de diálogo modales? ¡Debemos encontrar una manera de hacerlos aún más persistentes y molestos!". Realmente explica mucho sobre el software de microsoft.
Breton

3
@Disgruntled: No, no soy bretón, y el punto del artículo no es "La opción predeterminada es ..." sino "los usuarios no leen nada".
erikkallen 01 de

7

¡Deja de navegar este código funciona!

$(document).on("keydown", function (event) {        
   if (event.keyCode === 8) {
      event.preventDefault();
    }
  });

Pero para no restringir campos de texto pero otros

$(document).on("keydown", function (event) {
  if (event.which === 8 && !$(event.target).is("input, textarea")) {
   event.preventDefault();
  }
});

Para evitarlo para un campo específico, simplemente use

$('#myOtherField').on("keydown", function (event) {
  if (event.keyCode === 8 || event.which === 8) { 
   event.preventDefault(); 
  } 
});

En referencia a este a continuación!

Evite que BACKSPACE vuelva a navegar con jQuery (como la página de inicio de Google)


7

La mayoría de las respuestas están en jquery. Puede hacerlo perfectamente en Javascript puro, simple y no requiere biblioteca. Este artículo fue un buen punto de partida para mí, pero dado que keyIdentifier está en desuso, quería que este código fuera más seguro, así que agregué || e.keyCode == 8 a la instrucción if. Además, el código no funcionaba bien en Firefox, así que agregué return false; y ahora funciona perfectamente bien Aquí está:

<script type="text/javascript">
window.addEventListener('keydown',function(e){if(e.keyIdentifier=='U+0008'||e.keyIdentifier=='Backspace'||e.keyCode==8){if(e.target==document.body){e.preventDefault();return false;}}},true);
</script>

Este código funciona muy bien porque,

  1. Está en javascript puro (no se requiere biblioteca).
  2. No solo comprueba la tecla presionada, sino que confirma si la acción es realmente una acción de "retroceso" del navegador.
  3. Junto con lo anterior, el usuario puede escribir y eliminar texto de los cuadros de texto de entrada en la página web sin ningún problema al tiempo que evita la acción del botón de retroceso.
  4. Es corto, limpio, rápido y directo al grano.

Puede agregar console.log (e); para sus propósitos de prueba, y presione F12 en Chrome, vaya a la pestaña "consola" y presione "retroceso" en la página y mire dentro para ver qué valores se devuelven, luego puede apuntar a todos esos parámetros para mejorar aún más el código arriba para satisfacer sus necesidades.


6

Combinando soluciones dadas por "thetoolman" && "Biff MaGriff"

El siguiente código parece funcionar correctamente en IE 8 / Mozilla / Chrome

$(function () {
    var rx = /INPUT|TEXTAREA/i;
    var rxT = /RADIO|CHECKBOX|SUBMIT/i;

    $(document).bind("keydown keypress", function (e) {
        var preventKeyPress;
        if (e.keyCode == 8) {
            var d = e.srcElement || e.target;
            if (rx.test(e.target.tagName)) {
                var preventPressBasedOnType = false;
                if (d.attributes["type"]) {
                    preventPressBasedOnType = rxT.test(d.attributes["type"].value);
                }
                preventKeyPress = d.readOnly || d.disabled || preventPressBasedOnType;
            } else {preventKeyPress = true;}
        } else { preventKeyPress = false; }

        if (preventKeyPress) e.preventDefault();
    });
}); 

Agregar IMAGEN también puede ser útil.
mrswadge

Me decidí por este.
Corentin

5

No estoy seguro de por qué nadie acaba de responder esto: parece una pregunta técnica perfectamente razonable para preguntar si es posible.

No, no creo que haya una forma de navegador cruzado para desactivar el botón de retroceso. Sin embargo, sé que no está habilitado de forma predeterminada en FF en estos días.


3
Menos 1 por no responder la pregunta real y perder el tiempo
Andrew

4

Me costó encontrar una respuesta que no fuera de JQUERY. Gracias a Stas por ponerme en la pista.

Cromo: si no necesita soporte para varios navegadores, puede usar una lista negra, en lugar de una lista blanca. Esta versión JS pura funciona en Chrome, pero no en IE. No estoy seguro acerca de FF.

En Chrome (ver. 36, mediados de 2014), las pulsaciones de teclas que no están en una entrada o elemento contento parecen estar dirigidas a <BODY>. Esto hace posible usar una lista negra, que prefiero incluir en la lista blanca. IE usa el objetivo del último clic, por lo que puede ser un div o cualquier otra cosa. Eso hace que esto sea inútil en IE.

window.onkeydown = function(event) {
    if (event.keyCode == 8) {
    //alert(event.target.tagName); //if you want to see how chrome handles keypresses not on an editable element
        if (event.target.tagName == 'BODY') {
            //alert("Prevented Navigation");
            event.preventDefault();
        }
    }
}  

Cross Browser: para javascript puro, encontré que la respuesta de Stas es la mejor. Agregar una verificación de condición más para contenteditable lo hizo funcionar para mí *:

document.onkeydown = function(e) {stopDefaultBackspaceBehaviour(e);}
document.onkeypress = function(e) {stopDefaultBackspaceBehaviour(e);}

function stopDefaultBackspaceBehaviour(event) {
    var event = event || window.event;
    if (event.keyCode == 8) {
        var elements = "HTML, BODY, TABLE, TBODY, TR, TD, DIV";
        var d = event.srcElement || event.target;
        var regex = new RegExp(d.tagName.toUpperCase());
        if (d.contentEditable != 'true') { //it's not REALLY true, checking the boolean value (!== true) always passes, so we can use != 'true' rather than !== true/
            if (regex.test(elements)) {
                event.preventDefault ? event.preventDefault() : event.returnValue = false;
            }
        }
    }
}

* Tenga en cuenta que los IE [edit: y Spartan / TechPreview] tienen una "característica" que hace que los elementos relacionados con la tabla no sean editables . Si hace clic en uno de ellos y ENTONCES presiona la tecla de retroceso, navegará hacia atrás. Si no tiene correos editables <td>, esto no es un problema.


3

Esta solución es similar a otras que se han publicado, pero utiliza una lista blanca simple que lo hace fácilmente personalizable para permitir el retroceso en elementos específicos simplemente configurando el selector en la función .is ().

Lo uso en este formulario para evitar que el espacio de retroceso en las páginas navegue hacia atrás:

$(document).on("keydown", function (e) {
    if (e.which === 8 && !$(e.target).is("input:not([readonly]), textarea")) {
        e.preventDefault();
    }
});

2
Cuando el usuario usa contenteditable, esto lo deshabilitaría. Por lo tanto, es posible que desee agregar contenteditable = true en la lista blanca
Miguel

3

Para explicar un poco la excelente respuesta de @ erikkallen , aquí hay una función que permite todos los tipos de entrada basados ​​en el teclado, incluidos los introducidos en HTML5 :

$(document).unbind('keydown').bind('keydown', function (event) {
    var doPrevent = false;
    var INPUTTYPES = [
        "text", "password", "file", "date", "datetime", "datetime-local",
        "month", "week", "time", "email", "number", "range", "search", "tel",
        "url"];
    var TEXTRE = new RegExp("^" + INPUTTYPES.join("|") + "$", "i");
    if (event.keyCode === 8) {
        var d = event.srcElement || event.target;
        if ((d.tagName.toUpperCase() === 'INPUT' && d.type.match(TEXTRE)) ||
             d.tagName.toUpperCase() === 'TEXTAREA') {
            doPrevent = d.readOnly || d.disabled;
        } else {
            doPrevent = true;
        }
    }
    if (doPrevent) {
        event.preventDefault();
    }
});

Gracias, estoy usando esta respuesta! ¿Ha encontrado algún problema con estas soluciones hasta ahora?
Nearpoint

1
Recomiendo mover las declaraciones INPUTTYPES, TEXTRE fuera de la función para que no se recalculen en cada evento de keydown.
thetoolman

3

JavaScript - forma jQuery:

$(document).on("keydown", function (e) {
    if (e.which === 8 && !$(e.target).is("input, textarea")) {
        e.preventDefault();
    }
});

Javascript: la forma nativa que funciona para mí:

<script type="text/javascript">

//on backspace down + optional callback
function onBackspace(e, callback){
    var key;
    if(typeof e.keyIdentifier !== "undefined"){
        key = e.keyIdentifier;

    }else if(typeof e.keyCode !== "undefined"){
        key = e.keyCode;
    }
    if (key === 'U+0008' || 
        key === 'Backspace' || 
        key === 8) {
                    if(typeof callback === "function"){
                callback();
            }
            return true;
        }
    return false;
}

//event listener
window.addEventListener('keydown', function (e) {

    switch(e.target.tagName.toLowerCase()){
        case "input":
        case "textarea":
        break;
        case "body":
            onBackspace(e,function(){
                e.preventDefault();
            });

        break;
    }
}, true);
</script>

@MichaelPotter Estuvo bien para mi caso de uso, hace mucho tiempo. Por favor, siéntase libre de contribuir mejorando / alterando mi respuesta. ¡Gracias!
Vladimir Djuricic

2

Tuve algunos problemas con la solución aceptada y el complemento Select2.js; No pude eliminar caracteres en el cuadro editable ya que se estaba evitando la acción de eliminar. Esta fue mi solución:

//Prevent backwards navigation when trying to delete disabled text.
$(document).unbind('keydown').bind('keydown', function (event) {

    if (event.keyCode === 8) {

        var doPrevent = false,
            d = event.srcElement || event.target,
            tagName = d.tagName.toUpperCase(),
            type = (d.type ? d.type.toUpperCase() : ""),
            isEditable = d.contentEditable,
            isReadOnly = d.readOnly,
            isDisabled = d.disabled;

        if (( tagName === 'INPUT' && (type === 'TEXT' || type === 'PASSWORD'))
            || tagName === 'PASSWORD'
            || tagName === 'TEXTAREA') {
            doPrevent =  isReadOnly || isDisabled;
        }
        else if(tagName === 'SPAN'){
            doPrevent = !isEditable;
        }
        else {
            doPrevent = true;
        }
    }

    if (doPrevent) {
        event.preventDefault();
    }
});

Select2 crea un Span con un atributo de "contentEditable" que se establece en verdadero para el cuadro combinado editable en él. Agregué código para tener en cuenta el nombre de etiqueta y el atributo diferente. Esto resolvió todos mis problemas.

Editar: si no está utilizando el complemento de cuadro combinado Select2 para jquery, es posible que no necesite esta solución y que la solución aceptada sea mejor.


1
    document.onkeydown = function (e) {    
        e.stopPropagation();
        if ((e.keyCode==8  ||  e.keyCode==13) &&
            (e.target.tagName != "TEXTAREA") && 
            (e.target.tagName != "INPUT")) { 
            return false;
        }
    };

2
No deberías usar return false. Se recomienda e.preventDefault. También está deteniendo la propagación del evento para cada tecla y no solo para la tecla de retroceso. Finalmente, keyCode 13 es enter y la pregunta era sobre evitar la navegación hacia atrás con retroceso, pero esto evitaría que enter envíe el formulario o realice otras acciones.
Ninguno

1

Este código resuelve el problema en todos los navegadores:

onKeydown:function(e)
{
    if (e.keyCode == 8) 
    {
      var d = e.srcElement || e.target;
      if (!((d.tagName.toUpperCase() == 'BODY') || (d.tagName.toUpperCase() == 'HTML'))) 
      {
         doPrevent = false;
      }
       else
      {
         doPrevent = true;
      }
    }
    else
    {
       doPrevent = false;
    }
      if (doPrevent)
      {
         e.preventDefault();
       }

  }

1
Creo que este código no funciona como se esperaba debido a que d.tagname es DIVo TD.
Biff MaGriff

El código de Haseeb Akhtar funciona perfecto en Chrome y Firefox, ¡pero sorpresa! no en IE6-9 ¿Alguna sugerencia?
Martin Andersen

1

La forma más sencilla de evitar la navegación al presionar la tecla de retroceso

$(document).keydown(function () {
    if (event.keyCode == 8) {
        if (event.target.nodeName == 'BODY') {
            event.preventDefault();
        }
    }
});

Previene la navegación al presionar backspcae, y al mismo tiempo permite retroceder con todos los controles de entrada
Mohammed Irfan Mayan

Y no te pierdas la primera línea .. $ (document) .keydown (function () {
Mohammed Irfan Mayan

3
esto deshabilitará el botón de retroceso dentro de las áreas y entradas de texto
nodrog

1

Usando Dojo toolkit 1.7, esto funciona en IE 8:

require(["dojo/on", "dojo/keys", "dojo/domReady!"],
function(on, keys) {
    on(document.body,"keydown",function(evt){if(evt.keyCode == keys.BACKSPACE)evt.preventDefault()});
});

1

¿Ha probado la solución muy simple de simplemente agregar el siguiente atributo a su campo de texto de solo lectura:

onkeydown = "return false;"

Esto evitará que el navegador regrese al historial cuando se presione la tecla Retroceso en un campo de texto de solo lectura. Tal vez me estoy perdiendo tu verdadera intención, pero parece que esta sería la solución más simple para tu problema.


1

Una solución mucho más ordenada:

$(document).on('keydown', function (e) {
    var key = e == null ? event.keyCode : e.keyCode;
    if(key == 8 && $(document.activeElement.is(':not(:input)')))   //select, textarea
      e.preventDefault();
});

Alternativamente, solo puede verificar si

$(document.activeElement).is('body')

1

Versión javascript pura, que funciona en todos los navegadores:

document.onkeydown = function(e) {stopDefaultBackspaceBehaviour(e);}
document.onkeypress = function(e) {stopDefaultBackspaceBehaviour(e);}

function stopDefaultBackspaceBehaviour(event) {
  var event = event || window.event;
  if (event.keyCode == 8) {
    var elements = "HTML, BODY, TABLE, TBODY, TR, TD, DIV";
    var d = event.srcElement || event.target;
    var regex = new RegExp(d.tagName.toUpperCase());
    if (regex.test(elements)) {
      event.preventDefault ? event.preventDefault() : event.returnValue = false;
    }
  }
}

Por supuesto, puede usar "INPUT, TEXTAREA" y luego "if (! Regex.test (elements))". El primero funcionó bien para mí.


1

¿Actuación?

Estaba preocupado por el rendimiento e hice un violín: http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/

var stresstest = function(e, method, index){...

He analizado los métodos más prometedores que encontré en este hilo. Resulta que todos fueron muy rápidos y probablemente no causen problemas en términos de "lentitud" al escribir. El método más lento que miré fue de aproximadamente 125 ms para 10.000 llamadas en IE8. Que es 0.0125ms por golpe.

Encontré que los métodos publicados por Codenepal y Robin Maben son más rápidos ~ 0.001ms (IE8) pero tenga cuidado con las diferentes semánticas.

Quizás esto sea un alivio para alguien que introduce este tipo de funcionalidad en su código.


1

Respuesta erikkallen modificada:

$(document).unbind('keydown').bind('keydown', function (event) {

    var doPrevent = false, elem;

    if (event.keyCode === 8) {
        elem = event.srcElement || event.target;
        if( $(elem).is(':input') ) {
            doPrevent = elem.readOnly || elem.disabled;
        } else {
            doPrevent = true;
        }
    }

    if (doPrevent) {
        event.preventDefault();
        return false;
    }
});

1
Respuesta perfecta. La solución que obtuve de otros no funcionó en Firefox, pero esta funcionó perfectamente en los tres (Firefox, IE y Chrome) sin ningún problema. Gracias Prozi
Nikhil Dinesh

1

Esta solución funcionó muy bien cuando se probó.

Agregué un código para manejar algunos campos de entrada no etiquetados con entrada, y para integrarlo en una aplicación Oracle PL / SQL que genera un formulario de entrada para mi trabajo.

Mis dos centavos":

 if (typeof window.event != ''undefined'')
    document.onkeydown = function() {
    //////////// IE //////////////
    var src = event.srcElement;
    var tag = src.tagName.toUpperCase();
    if (event.srcElement.tagName.toUpperCase() != "INPUT"
        && event.srcElement.tagName.toUpperCase() != "TEXTAREA"
        || src.readOnly || src.disabled 
        )
        return (event.keyCode != 8);
    if(src.type) {
       var type = ("" + src.type).toUpperCase();
       return type != "CHECKBOX" && type != "RADIO" && type != "BUTTON";
       }
   }
else
   document.onkeypress = function(e) {
   //////////// FireFox 
   var src = e.target;
   var tag = src.tagName.toUpperCase();
   if ( src.nodeName.toUpperCase() != "INPUT" && tag != "TEXTAREA"
      || src.readOnly || src.disabled )
      return (e.keyCode != 8);
    if(src.type) {
      var type = ("" + src.type).toUpperCase();
      return type != "CHECKBOX" && type != "RADIO" && type != "BUTTON";
      }                              
   }

1

Creé un proyecto NPM con una versión limpia del actualmente aceptado (de erikkallen)

https://github.com/slorber/backspace-disabler

Utiliza básicamente los mismos principios pero:

  • Sin dependencia
  • Apoyo a contenteditable
  • Código base más legible / mantenible
  • Será compatible, ya que mi empresa lo utilizará en la producción.
  • Licencia MIT

var Backspace = 8;

// See http://stackoverflow.com/questions/12949590/how-to-detach-event-in-ie-6-7-8-9-using-javascript
function addHandler(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + type, handler);
    } else {
        element["on" + type] = handler;
    }
}
function removeHandler(element, type, handler) {
    if (element.removeEventListener) {
        element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
        element.detachEvent("on" + type, handler);
    } else {
        element["on" + type] = null;
    }
}




// Test wether or not the given node is an active contenteditable,
// or is inside an active contenteditable
function isInActiveContentEditable(node) {
    while (node) {
        if ( node.getAttribute && node.getAttribute("contenteditable") === "true" ) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
}



var ValidInputTypes = ['TEXT','PASSWORD','FILE','EMAIL','SEARCH','DATE'];

function isActiveFormItem(node) {
    var tagName = node.tagName.toUpperCase();
    var isInput = ( tagName === "INPUT" && ValidInputTypes.indexOf(node.type.toUpperCase()) >= 0 );
    var isTextarea = ( tagName === "TEXTAREA" );
    if ( isInput || isTextarea ) {
        var isDisabled = node.readOnly || node.disabled;
        return !isDisabled;
    }
    else if ( isInActiveContentEditable(node) ) {
        return true;
    }
    else {
        return false;
    }
}


// See http://stackoverflow.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back
function disabler(event) {
    if (event.keyCode === Backspace) {
        var node = event.srcElement || event.target;
        // We don't want to disable the ability to delete content in form inputs and contenteditables
        if ( isActiveFormItem(node) ) {
            // Do nothing
        }
        // But in any other cases we prevent the default behavior that triggers a browser backward navigation
        else {
            event.preventDefault();
        }
    }
}


/**
 * By default the browser issues a back nav when the focus is not on a form input / textarea
 * But users often press back without focus, and they loose all their form data :(
 *
 * Use this if you want the backspace to never trigger a browser back
 */
exports.disable = function(el) {
    addHandler(el || document,"keydown",disabler);
};

/**
 * Reenable the browser backs
 */
exports.enable = function(el) {
    removeHandler(el || document,"keydown",disabler);
};

1

Aquí está mi reescritura de la respuesta más votada. Traté de verificar element.value! == undefined (ya que algunos elementos como pueden no tener atributo html pero pueden tener una propiedad de valor de JavaScript en algún lugar de la cadena del prototipo), sin embargo, eso no funcionó muy bien y tenía muchos casos extremos. No parece haber una buena manera de hacer esto a prueba del futuro, por lo que una lista blanca parece la mejor opción.

Esto registra el elemento al final de la fase de burbuja de eventos, por lo que si desea manejar Retroceso de cualquier manera personalizada, puede hacerlo en otros controladores.

Esto también verifica la instancia de HTMLTextAreElement, ya que uno podría teóricamente tener un componente web que hereda de eso.

Esto no verifica el contenido Editable (combinar con otras respuestas).

https://jsfiddle.net/af2cfjc5/15/

var _INPUTTYPE_WHITELIST = ['text', 'password', 'search', 'email', 'number', 'date'];

function backspaceWouldBeOkay(elem) {
    // returns true if backspace is captured by the element
    var isFrozen = elem.readOnly || elem.disabled;
    if (isFrozen) // a frozen field has no default which would shadow the shitty one
        return false;
    else {
        var tagName = elem.tagName.toLowerCase();
        if (elem instanceof HTMLTextAreaElement) // allow textareas
            return true;
        if (tagName=='input') { // allow only whitelisted input types
            var inputType = elem.type.toLowerCase();
            if (_INPUTTYPE_WHITELIST.includes(inputType))
                return true;
        }   
        return false; // everything else is bad
    }
}

document.body.addEventListener('keydown', ev => {
    if (ev.keyCode==8 && !backspaceWouldBeOkay(ev.target)) {
        //console.log('preventing backspace navigation');
        ev.preventDefault();
    }
}, true); // end of event bubble phase

0

Sitepoint: desactivar de nuevo para Javascript

event.stopPropagation()y event.preventDefault()no hacer nada en IE. Sin embargo, tuve que enviar la devolución event.keyCode == 11(solo elegí algo) en lugar de solo decir "if not = 8, run the event"que funcionara. event.returnValue = falseTambién funciona.


0

Otro método usando jquery

    <script type="text/javascript">

    //set this variable according to the need within the page
    var BACKSPACE_NAV_DISABLED = true;

    function fnPreventBackspace(event){if (BACKSPACE_NAV_DISABLED && event.keyCode == 8) {return false;}}
    function fnPreventBackspacePropagation(event){if(BACKSPACE_NAV_DISABLED && event.keyCode == 8){event.stopPropagation();}return true;}

    $(document).ready(function(){ 
        if(BACKSPACE_NAV_DISABLED){
            //for IE use keydown, for Mozilla keypress  
            //as described in scr: http://www.codeproject.com/KB/scripting/PreventDropdownBackSpace.aspx
            $(document).keypress(fnPreventBackspace);
            $(document).keydown(fnPreventBackspace);

            //Allow Backspace is the following controls 
            var jCtrl = null;
            jCtrl = $('input[type="text"]');
            jCtrl.keypress(fnPreventBackspacePropagation);
            jCtrl.keydown(fnPreventBackspacePropagation);

            jCtrl = $('input[type="password"]');
            jCtrl.keypress(fnPreventBackspacePropagation);
            jCtrl.keydown(fnPreventBackspacePropagation);

            jCtrl = $('textarea');
            jCtrl.keypress(fnPreventBackspacePropagation);
            jCtrl.keydown(fnPreventBackspacePropagation);

            //disable backspace for readonly and disabled
            jCtrl = $('input[type="text"][readonly="readonly"]')
            jCtrl.keypress(fnPreventBackspace);
            jCtrl.keydown(fnPreventBackspace);

            jCtrl = $('input[type="text"][disabled="disabled"]')
            jCtrl.keypress(fnPreventBackspace);
            jCtrl.keydown(fnPreventBackspace);
        }
    }); 

    </script>

Tenga en cuenta que esto no funciona si los controles (cuadro de texto) se han agregado dinámicamente.
CodeNepal

0

He estado usando esto en mi código por algún tiempo. Escribo pruebas en línea para estudiantes y me encontré con el problema cuando los estudiantes presionaron la tecla de retroceso durante su prueba y los llevaría de vuelta a la pantalla de inicio de sesión. ¡Frustrante! Funciona en FF seguro.

document.onkeypress = Backspace;
function Backspace(event) {
    if (event.keyCode == 8) {
        if (document.activeElement.tagName == "INPUT") {
            return true;
        } else {
            return false;
        }
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.