Como posso impedir que a tecla backspace navegue de volta?

275

No IE, eu posso fazer isso com o jQuery (terrivelmente fora do padrão, mas funcionando)

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

Mas é possível fazer de uma maneira que funcione no Firefox ou de um modo cruzado para obter um bônus?

Para o registro:

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

faz nada.

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

resolve o problema, mas torna a chave de backspace inutilizável na página, o que é ainda pior que o comportamento original.

EDIT: A razão pela qual faço isso é que não estou criando uma página da Web simples, mas um aplicativo grande. É incrivelmente chato perder 10 minutos de trabalho só porque você pressionou o backspace no lugar errado. A proporção entre evitar erros e usuários irritantes deve estar muito acima de 1000/1, impedindo que a tecla backspace navegue de volta.

EDIT2: Eu estou não tentar impedir a navegação história, apenas acidentes.

EDIT3: comentário @brentonstrines (movido para cá porque a pergunta é muito popular): Esta é uma 'correção' de longo prazo, mas você pode apoiar seu bug do Chromium para alterar esse comportamento no webkit

erikkallen
fonte
137
Porque a tecla backspace está sobrecarregada. Você pode não ter percebido, mas provavelmente o usa o tempo todo para apagar as letras digitadas em um campo de texto. Alguns de meus clientes estão tendo problemas para fazer com que a página volte, então essas são informações úteis. Ninguém, a não ser vocês, palhaços, sabe que o backspace deve voltar uma página. Isso é algo que eu nunca soube, e é um comportamento hostil para um navegador. Eu acho que todas as páginas devem desativar esse comportamento.
30909 Breton
80
Por que as pessoas acham isso estranho? Usar o backspace para navegação é um atalho muito burro! existem tantos campos de texto dos quais os usuários podem querer excluir texto - imagine ter uma resposta longa do SO, alternar para outra janela para verificar algo e, em seguida, você voltar e clicar na área de edição, pressione backspace para remover uma palavra e de repente, o navegador retorna uma página e você potencialmente perdeu tudo o que acabou de escrever.
22440 Peter Boughton
57
Por que eu quero fazer isso? Não estou criando um site, mas um aplicativo da web. Alguns campos de entrada são somente leitura e, nesse caso, parecem editáveis, mas se você pressionar backspace, sairá da página. A proporção de prensas backspace que pretendem prensas backspace navegar de volta vs. tentando apagar algo é provavelmente muito menos do que 1 / 1000.
erikkallen
42
A questão é como fazer isso, e não sua opinião sobre se é uma boa ideia ou não. Sem conhecer os detalhes do projeto, suas opiniões não têm sentido. Meu cliente solicitou especificamente esse comportamento para um dos meus projetos e uma resposta real em vez de "Por que você gostaria de fazer isso?" Seria útil.
Nenhum
7
Essa é uma 'correção' de longo prazo, mas você pode apoiar o bug do Chromium para alterar esse comportamento no webkit: code.google.com/p/chromium/issues/detail?id=144832
brentonstrine

Respostas:

335

Esse código resolve o problema, pelo menos no IE e no Firefox (não testei nenhum outro, mas eu lhe dou uma chance razoável de funcionar se o problema existir em outros 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;
        }
    }
});
erikkallen
fonte
6
Quebra campos de senha.
Hemlock 12/03
7
Como Hemlock afirmou - verifique d.type.toUpperCase() === 'PASSWORD'também. Caso contrário, parece bom
stevendesu
17
Como você já está usando o jQueryif( $(d).is( ":input" ) )...
Paul Alexander
23
É chato que isso tenha que ser uma lista de permissões, em vez de poder colocar na lista negra a funcionalidade "voltar". Você pode adicionar um cheque d.isContentEditableaqui.
iono 12/09
3
Eu criei um projeto NPM com uma versão limpa da resposta atualmente aceita: github.com/slorber/backspace-disabler (também apoiar contenteditables e não tem nenhuma dependência)
Sebastien Lorber
62

Esse código funciona em todos os navegadores e engole a tecla backspace quando não estiver em um elemento do formulário ou se o elemento do formulário estiver desativado | readOnly. Também é eficiente, o que é importante quando está sendo executado em todas as chaves digitadas.

$(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();
            }
        }
    });
});
thetoolman
fonte
1
Por favor, teste meu exemplo, você pode querer atualizar seu código adequadamente.
precisa saber é o seguinte
10
Prefiro isso à solução da @ erikkallen, porque é mais limpa. No entanto, eu queria que botões de envio, botões de opção e caixas de seleção também fossem ignorados; portanto, mudei o if () para este: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
@ thetoolman, veja meu comentário sobre a resposta de erikallen. Isso também deve ser responsável contentEditable.
sacudida
10
@MaffooClock: você pode ser mais conciso com.is(':checkbox,:radio,:submit')
cdmckay
1
@cdmckay: Não acredito que não escrevi dessa maneira em primeiro lugar. Obrigado por limpeza que por todos nós :)
Matthew Clark
41

As outras respostas aqui estabeleceram que isso não pode ser feito sem os elementos da lista de permissões nos quais o Backspace é permitido. Essa solução não é ideal porque a lista de permissões não é tão direta quanto meramente as áreas de texto e as entradas de texto / senha, mas é repetidamente considerada incompleta e precisando ser atualizada.

No entanto, como o objetivo de suprimir a funcionalidade de backspace é meramente impedir que os usuários percam dados acidentalmente, a solução beforeunload é boa porque o pop-up modal é surpreendente - os pop-ups modais são ruins quando acionados como parte de um fluxo de trabalho padrão, porque o usuário se acostuma a dispensá-los sem lê-los, e eles são irritantes. Nesse caso, o pop-up modal apareceria apenas como uma alternativa a uma ação rara e surpreendente e, portanto, é aceitável.

O problema é que um modal onbeforeunload não deve aparecer sempre que o usuário navega para fora da página (como ao clicar em um link ou ao enviar um formulário), e não queremos iniciar a lista de permissões ou a lista negra de condições específicas antes da carga.

A combinação ideal de vantagens e desvantagens para uma solução generalizada é a seguinte: acompanhe se o backspace está pressionado e, somente se necessário, apareça o modal onbeforeunload. Em outras palavras:

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

Isso foi testado para funcionar no IE7 +, FireFox, Chrome, Safari e Opera. Basta soltar essa função no seu global.js e chamá-la de qualquer página em que você não queira que os usuários percam acidentalmente seus dados.

Observe que um modal onbeforeunload pode ser acionado apenas uma vez; portanto, se o usuário pressionar backspace novamente, o modal não será acionado novamente.

Observe que isso não será acionado em eventos de alteração de hash, no entanto, nesse contexto, você pode usar outras técnicas para impedir que os usuários percam acidentalmente seus dados.

Vladimir Kornea
fonte
2
Acabei de adicionar esta mesma solução e vi este post na parte inferior da página LOL. Uma diferença que tenho é definir lastUserInputWasBackspace = false antes da declaração "Você tem certeza ...", para que você não apareça o pop-up se clicar no botão voltar depois de ver o pop-up (por isso é consistente com comportamento influenciado pelo backspace).
David Russell
1
@ user2407309 Removi meu comentário (não uma reclamação) sobre o firefox que não está funcionando com sua solução. Houve um problema com meu depurador. Minhas desculpas por editar / quebrar seu código. Percebo agora que ultrapassei meus limites (edição), me perdoe. Lamento sinceramente e não quis reclamar da sua maravilhosa solução para este problema. Mais uma vez, minhas desculpas. Esse código funciona bem. Acredito que esta é a melhor resposta e recomendo-lhe por isso.
Charles Byrne
1
Essa solução funcionou na minha máquina local, mas quando a mudei, o cliente (pelo menos alguns deles) perdeu a funcionalidade de metade do aplicativo. Acho que algo está rejeitando, mas não faço ideia do que.
Steve
1
@ Steve, raro ou não, se houver algum problema com a função, essas informações pertencerão aqui. Eu só quero saber se realmente existe um problema.
Vladimir Kornea
1
Solução agradável, mas infelizmente, se um usuário pressionar acidentalmente o backspace duas vezes, ele ainda retornará. (pelo menos no firefox)
Remco de Zwart
26

Uma solução mais 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();
  }
})
Darwayne
fonte
1
Isso é muito mais conciso e, pelo que sei, funciona também. Por que a resposta mais popular tem todos esses tipos de entradas e parece mais complicada? É mais confiável?
Nearpoint
1
A resposta mais popular foi a primeira a responder à pergunta, portanto, os altos votos.
Darwayne 12/09
4
quando os campos somente leitura estão focados exclusão navega ainda voltar em cromo
Will D
16

Modificação da resposta de erikkallen para abordar diferentes tipos de entrada

Descobri que um usuário empreendedor pode pressionar backspace em uma caixa de seleção ou em um botão de opção em uma tentativa vã de limpá-lo. Em vez disso, eles navegariam para trás e perderiam todos os dados.

Essa alteração deve resolver esse problema.

Nova edição para tratar de divs editáveis ​​de conteúdo

    //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();
    });

Exemplo
Para testar faça 2 arquivos.

starthere.htm - abra isso primeiro para ter um lugar para voltar

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

test.htm - Irá retroceder quando o backspace for pressionado enquanto a caixa de seleção ou o envio estiver focado (alcançado por tabulação). Substitua pelo meu código para corrigir.

<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>
Biff MaGriff
fonte
Qual navegador você viu pressionar backspace no rádio | caixa de seleção | enviar -> função de retorno? Eu não vi um navegador fazer isso ..
thetoolman
Internet Explorer 8 e Chrome
Biff MaGriff,
2
Tentei várias outras soluções nesse segmento, mas este funcionou bem em todas as minhas situações e tinha o código mais limpo e fácil de entender. Obrigado.
Ezward
Você tentou @Darwayne Estou curioso para saber por que um é tão curto e isso é é mais complexa, mas ambos parecem funcionar exatamente o mesmo para mim
NearPoint
Isso funciona em links? Eu tenho um aplicativo ASP.Net com um botão de imagem para remover um item. Essa é a única coisa que este não tem funcionado tão longe ...
Steve
8

Com base nos comentários, parece que você deseja impedir que as pessoas percam informações em formulários, se elas pressionarem backspace para excluir, mas o campo não estiver focado.

Nesse caso, você deseja examinar o manipulador de eventos onunload . O Stack Overflow o usa - se você tentar sair de uma página quando começar a escrever uma resposta, será exibido um aviso.

DisgruntledGoat
fonte
4
desculpe que foi um comentário rude. O que quero dizer é que o usuário provavelmente não quer ser repreendido por fazer algo que nem sabia que estava errado. Por que não comer a chave silenciosamente com um pressionamento de tecla? O objetivo não é impedir completamente o usuário de sair da página, mas proteger-se contra esse erro comum. Além disso, os diálogos pop-up não são muito eficazes ou úteis. Os usuários não os lêem. Tem certeza de que deseja sair da página? OK! Não, espere, espere, eu não queria sair da página .. oops, tarde demais.
Breton
3
OK, pegue ou largue. Acho que você está tentando projetar demais um problema que realmente não existe, ou que pelo menos não é importante. E, na minha experiência, são apenas usuários avançados que clicam em "OK" em diálogos desconhecidos sem lê-los corretamente. ;) #
DisgruntledGoat
3
Você e Breton são a mesma pessoa? De qualquer forma, você meio que deu um tiro no pé - o artigo diz "a resposta padrão é Cancelar". Ao ver a caixa de diálogo sobre sair da página, eles pressionam "Cancelar" e, portanto, não saem da página. Embora seja necessário observar que as opções do Chrome nessa caixa de diálogo são "Sair desta página" e "Permanecer nesta página", que são muito claras.
DisgruntledGoat
1
Não, ele não sou eu, mas já encontrei esse link antes. Eu acho que os comentários são hilários. "O que !? as pessoas ignoram as caixas de diálogo modais? Precisamos encontrar uma maneira de torná-las ainda mais persistentes e irritantes!". Realmente explica muito sobre o software da Microsoft.
bretão
3
@ Desapontado: Não, eu não sou bretão, e o objetivo do artigo não é "A opção padrão é ...", mas "Os usuários não lêem nada".
erikkallen
7

Pare de navegar neste código funciona!

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

Mas para não restringir os campos de texto, mas outros

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

Para evitá-lo para um campo específico, basta usar

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

Referindo-se a este abaixo!

Impedir que o BACKSPACE navegue de volta com o jQuery (como a página inicial do Google)

Syed Ehtsham Abbas
fonte
7

A maioria das respostas está em jquery. Você pode fazer isso perfeitamente em Javascript puro, simples e sem necessidade de biblioteca. Este artigo foi um bom ponto de partida para mim, mas como keyIdentifier está obsoleto, eu queria que esse código fosse mais seguro, então adicionei || e.keyCode == 8 à instrução if. Além disso, o código não estava funcionando bem no Firefox, então adicionei return false; e agora funciona perfeitamente bem. Aqui 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>

Esse código funciona muito bem porque,

  1. Está em javascript puro (nenhuma biblioteca é necessária).
  2. Não apenas verifica a tecla pressionada, mas também confirma se a ação é realmente uma ação de "retorno" do navegador.
  3. Juntamente com o acima, o usuário pode digitar e excluir texto das caixas de texto de entrada na página da Web sem problemas, enquanto ainda impede a ação do botão Voltar.
  4. É curto, limpo, rápido e direto ao ponto.

Você pode adicionar console.log (e); para seus objetivos de teste, e pressione F12 no chrome, vá para a guia "console" e pressione "backspace" na página e olhe dentro dela para ver quais valores são retornados. Em seguida, você pode direcionar todos esses parâmetros para aprimorar ainda mais o código acima para atender às suas necessidades.

Tarik
fonte
6

Combinando soluções fornecidas por "thetoolman" e& "Biff MaGriff"

O código a seguir parece funcionar corretamente no 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();
    });
}); 
CodeNepal
fonte
Adicionar IMAGE também pode ser útil.
mrswadge
Eu decidi sobre este.
Corentin
5

Não sei por que ninguém acabou de responder a isso - parece uma pergunta técnica perfeitamente razoável para perguntar se é possível.

Não, não acho que exista uma maneira entre navegadores de desativar o botão backspace. Sei que não está habilitado por padrão no FF atualmente.

brabster
fonte
3
Menos 1 por não responder a questão real e perder tempo
Andrew
4

Foi difícil encontrar uma resposta que não fosse JQUERY. Agradeço a Stas por me colocar na pista.

Chrome: se você não precisar de suporte entre navegadores, basta usar uma lista negra, em vez da lista de permissões. Esta versão JS pura funciona no Chrome, mas não no IE. Não tenho certeza sobre FF.

No Chrome (versão 36, meados de 2014), os pressionamentos de tecla que não estão em um elemento de entrada ou conteúdo editável parecem ser direcionados <BODY>. Isso possibilita o uso de uma lista negra, que eu prefiro na lista de permissões. O IE usa o destino do último clique - portanto, pode ser um div ou qualquer outra coisa. Isso torna isso inútil no 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();
        }
    }
}  

Navegador Cruzado: para javascript puro, achei a resposta da Stas a melhor. A adição de mais uma verificação de condição para contenteditable fez com que funcionasse para mim *:

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;
            }
        }
    }
}

* Observe que os IEs [edit: e Spartan / TechPreview] têm um "recurso" que torna os elementos relacionados à tabela não editáveis . Se você clicar em um deles e, em seguida, pressionar backspace, ele voltará. Se você não possui <td>s editáveis , isso não é problema.

Josiah
fonte
3

Essa solução é semelhante a outras postadas, mas usa uma lista de desbloqueio simples, tornando-a facilmente personalizável para permitir o backspace em elementos especificados, basta definir o seletor na função .is ().

Eu o uso neste formulário para impedir que o backspace nas páginas navegue de volta:

$(document).on("keydown", function (e) {
    if (e.which === 8 && !$(e.target).is("input:not([readonly]), textarea")) {
        e.preventDefault();
    }
});
Nenhum
fonte
2
Quando o usuário usa contenteditable, isso o desabilita. Então você pode querer adicionar o contenteditable = true na whitelist
Miguel
3

Para elaborar um pouco a excelente resposta de @ erikkallen , aqui está uma função que permite todos os tipos de entrada baseados em teclado, incluindo os introduzidos no 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();
    }
});
Gingi
fonte
Obrigado, estou usando esta resposta! Você encontrou algum problema com essas soluções até agora?
Nearpoint
1
Eu recomendo mover as declarações INPUTTYPES, TEXTRE da função para que elas não sejam recalculadas em todos os eventos de pressionamento de tecla.
Thetoolman
3

Maneira do jQuery do JavaScript -:

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

Javascript - a maneira nativa, que funciona para mim:

<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>
Vladimir Djuricic
fonte
@MichaelPotter Tudo bem para o meu caso de uso, há muito tempo. Por favor, sinta-se à vontade para contribuir melhorando / alterando minha resposta. THX!
Vladimir Djuricic
2

Eu tive alguns problemas com a solução aceita e o plug-in Select2.js; Não pude excluir caracteres na caixa editável porque a ação de exclusão estava sendo impedida. Esta foi a minha solução:

//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();
    }
});

O Select2 cria um Span com um atributo "contentEditable", definido como true para a caixa de combinação editável. Eu adicionei o código para levar em conta o spanName tagName e o atributo diferente. Isso resolveu todos os meus problemas.

Edit: Se você não estiver usando o plug-in de caixa de combinação Select2 para jquery, essa solução poderá não ser necessária e a solução aceita poderá ser melhor.

Pytry
fonte
1
    document.onkeydown = function (e) {    
        e.stopPropagation();
        if ((e.keyCode==8  ||  e.keyCode==13) &&
            (e.target.tagName != "TEXTAREA") && 
            (e.target.tagName != "INPUT")) { 
            return false;
        }
    };
elico3000
fonte
2
Você não deve usar return false. e.preventDefault é recomendado. Além disso, você está parando a propagação do evento para cada chave e não apenas no backspace. Por fim, o keyCode 13 é enter e a pergunta era sobre impedir a navegação de retorno com backspace, mas isso impediria o envio do formulário ou a execução de outras ações.
Nenhum
1

Este código resolve o problema em todos os 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();
       }

  }
Haseeb Akhtar
fonte
1
Acho que esse código não funciona como esperado devido ao d.tagname ser DIVou TD.
Biff MaGriff
O código do Haseeb Akhtar funciona perfeitamente no Chrome e Firefox, mas surpresa !! não no IE6-9 Alguma sugestão?
Martin Andersen
1

Maneira mais simples de impedir a navegação ao pressionar backspace

$(document).keydown(function () {
    if (event.keyCode == 8) {
        if (event.target.nodeName == 'BODY') {
            event.preventDefault();
        }
    }
});
Mohammed Irfan Mayan
fonte
Navegação previne a pressionar backspcae, e ao mesmo tempo permite backspace com em todos os controles de entrada
Mohammed Irfan maia
E não perca a primeira linha .. $ (document) .keydown (function () {
Mohammed Irfan Mayan
3
isso irá desativar o backbutton dentro textareas e insumos
nodrog
1

Usando o Dojo toolkit 1.7, isso funciona no 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()});
});
Chris V
fonte
1

Você já tentou a solução muito simples de adicionar o seguinte atributo ao seu campo de texto somente leitura:

onkeydown = "return false;"

Isso impedirá que o navegador volte no histórico quando a tecla Backspace for pressionada em um campo de texto somente leitura. Talvez eu esteja perdendo sua verdadeira intenção, mas parece que essa seria a solução mais simples para o seu problema.

B-Dog
fonte
1

Uma solução muito mais limpa -

$(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();
});

Como alternativa, você só pode verificar se

$(document.activeElement).is('body')
Robin Maben
fonte
1

Versão javascript pura, que funciona em todos os 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;
    }
  }
}

Claro que você pode usar "INPUT, TEXTAREA" e usar "if (! Regex.test (elements))" então. O primeiro funcionou bem para mim.

Stanislav Parkhomenko
fonte
1

Atuação?

Eu estava preocupado com o desempenho e criei um violino: http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/

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

Analisei os métodos mais promissores que encontrei neste tópico. Acontece que todos eles foram muito rápidos e provavelmente não causam problemas em termos de "lentidão" ao digitar. O método mais lento que eu observei foi de cerca de 125 ms para 10.000 chamadas no IE8. Qual é 0,0125ms por curso.

Eu achei os métodos postados por Codenepal e Robin Maben os mais rápidos ~ 0.001ms (IE8), mas cuidado com as semânticas diferentes.

Talvez isso seja um alívio para alguém que introduz esse tipo de funcionalidade em seu código.

felvhage
fonte
1

Resposta 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;
    }
});
Jacek Pietal
fonte
1
Resposta perfeita. A solução que obtive de outros não funcionou no firefox, mas esta funcionou perfeitamente nos três (Firefox, IE e crome) sem nenhum problema. Obrigado Prozi.
Nikhil Dinesh
1

Esta solução funcionou muito bem quando testada.

Eu adicionei algum código para lidar com alguns campos de entrada não marcados com entrada e para integrar um aplicativo Oracle PL / SQL que gera um formulário de entrada para o meu trabalho.

Meus dois 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";
      }                              
   }
Luis Cuellar
fonte
1

Criei um projeto NPM com uma versão limpa do atualmente aceito (de erikkallen)

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

Ele usa basicamente os mesmos princípios, mas:

  • Sem dependência
  • Suporte para conteúdo editável
  • Base de código mais legível / sustentável
  • Será suportado, pois será utilizado na produção pela minha empresa
  • Licença 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);
};
Sebastien Lorber
fonte
1

Aqui está minha reescrita da resposta mais votada. Tentei verificar element.value! == indefinido (já que alguns elementos como podem não ter atributo html, mas podem ter uma propriedade de valor javascript em algum lugar da cadeia de protótipos), no entanto, isso não funcionou muito bem e teve muitos casos de borda. Não parece haver uma boa maneira de fazer isso à prova do futuro; portanto, uma lista de permissões parece ser a melhor opção.

Isso registra o elemento no final da fase de bolha do evento; portanto, se você quiser manipular o Backspace de qualquer maneira personalizada, poderá fazê-lo em outros manipuladores.

Isso também verifica a instância do HTMLTextAreElement, pois, teoricamente, é possível ter um componente da Web que herda disso.

Isso não verifica o contentEditable (combine com outras respostas).

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
ninjagecko
fonte
0

Ponto do site: desativar novamente para Javascript

event.stopPropagation()e event.preventDefault()não faça nada no IE. Eu tive que enviar retorno event.keyCode == 11(eu só peguei algo) em vez de apenas dizer "if not = 8, run the event"para fazê-lo funcionar, no entanto. event.returnValue = falsetambém funciona.

Tom
fonte
0

Outro 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>
CodeNepal
fonte
Observe que isso não funciona se os controles (caixa de texto) foram adicionados dinamicamente.
CodeNepal
0

Estou usando isso no meu código há algum tempo. Escrevo testes on-line para os alunos e me deparei com o problema quando eles pressionavam o backspace durante o teste, e isso os levava de volta à tela de login. Frustrante! Funciona no FF, com certeza.

document.onkeypress = Backspace;
function Backspace(event) {
    if (event.keyCode == 8) {
        if (document.activeElement.tagName == "INPUT") {
            return true;
        } else {
            return false;
        }
    }
}
bronzeado
fonte