Comment empêcher la touche de retour arrière de revenir en arrière?

275

Sur IE, je peux le faire avec jQuery (terriblement non standard, mais qui fonctionne)

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

Mais est-il possible de faire d'une manière qui fonctionne sur Firefox, ou d'une manière multi-navigateur pour un bonus?

Pour mémoire:

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

ne fait rien.

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

résout le problème, mais rend la clé de retour arrière inutilisable sur la page, ce qui est encore pire que le comportement d'origine.

EDIT: La raison pour laquelle je fais cela est que je ne crée pas une simple page Web mais une grande application. C'est incroyablement ennuyeux de perdre 10 minutes de travail simplement parce que vous avez appuyé sur la touche de retour au mauvais endroit. Le rapport entre la prévention des erreurs et les utilisateurs ennuyeux devrait être bien supérieur à 1000/1 en empêchant la touche de retour arrière de revenir en arrière.

EDIT2: Je n'essaie pas d'empêcher la navigation dans l'historique, juste les accidents.

EDIT3: Commentaire @brentonstrines (déplacé ici car la question est si populaire): il s'agit d'un «correctif» à long terme, mais vous pouvez apporter votre soutien derrière le bogue Chromium pour changer ce comportement dans le webkit

erikkallen
la source
137
Parce que la clé de retour arrière est surchargée. Vous ne l'avez peut-être pas remarqué, mais vous l'utilisez probablement tout le temps pour effacer les lettres que vous venez de taper dans un champ de texte. Certains de mes clients ont eu des problèmes avec cela pour faire revenir la page, donc ce sont des informations utiles. Personne d'autre que vous, clowns, ne sait que le retour arrière est censé remonter d'une page. C'est quelque chose que je n'ai jamais su, et c'est un comportement tout à fait hostile pour un navigateur. Je pense que toutes les pages devraient désactiver ce comportement.
Breton
80
Pourquoi les gens pensent-ils que c'est étrange? Utiliser le retour arrière pour la navigation est un raccourci vraiment stupide! il y a tellement de champs de texte que les utilisateurs pourraient vouloir supprimer du texte - imaginez avoir une longue réponse SO, passer à une autre fenêtre pour vérifier quelque chose, puis vous revenez et cliquez mal sur la zone d'édition, appuyez sur la touche de retour arrière pour supprimer un mot et soudain, le navigateur recule d'une page et vous avez potentiellement perdu tout ce que vous venez d'écrire.
Peter Boughton
57
Pourquoi je veux faire ça? Je ne crée pas un site Web mais une application Web. Certains champs de saisie sont en lecture seule, auquel cas ils semblent modifiables, mais si vous appuyez sur la touche de retour arrière, vous quittez la page. Le rapport entre les pressions de retour arrière ayant l'intention de revenir en arrière et les pressions de retour arrière essayant d'effacer quelque chose est probablement bien inférieur à 1 / 1000.
erikkallen
42
La question est de savoir comment procéder, pas votre avis sur le fait de savoir si c'est une bonne idée ou non. Sans connaître les détails du projet, vos opinions sont dénuées de sens. Mon client a spécifiquement demandé ce comportement pour l'un de mes projets et une vraie réponse plutôt que "Pourquoi voudriez-vous faire ça?" serait utile.
Aucun
7
Il s'agit d'un «correctif» à long terme, mais vous pouvez apporter votre soutien derrière le bogue Chromium pour modifier ce comportement dans le kit Web
brentonstrine

Réponses:

335

Ce code résout le problème, au moins dans IE et Firefox (je n'en ai testé aucun autre, mais je lui donne une chance raisonnable de fonctionner si le problème existe même dans d'autres navigateurs).

// 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
la source
6
Casse les champs de mot de passe.
Hemlock
7
Comme l'a dit Hemlock - vérifiez d.type.toUpperCase() === 'PASSWORD'également. Sinon, ça a l'air bien
stevendesu
17
Puisque vous utilisez déjà jQueryif( $(d).is( ":input" ) )...
Paul Alexander
23
Cela craint qu'il ne s'agisse d'une liste blanche, plutôt que de pouvoir mettre sur liste noire la fonctionnalité "retour". Vous pouvez ajouter un chèque d.isContentEditableici.
iono
3
J'ai créé un projet NPM avec une version propre de la réponse actuellement acceptée: github.com/slorber/backspace-disabler (il prend également en charge contenteditables et n'a aucune dépendance)
Sebastien Lorber
62

Ce code fonctionne sur tous les navigateurs et avale la touche de retour arrière lorsqu'il n'est pas sur un élément de formulaire, ou si l'élément de formulaire est désactivé | en lecture seule. Il est également efficace, ce qui est important lorsqu'il s'exécute sur chaque clé tapée.

$(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
la source
1
Veuillez tester mon exemple, vous souhaiterez peut-être mettre à jour votre code en conséquence.
Biff MaGriff
10
Je préfère cela à la solution de @ erikkallen car c'est plus propre. Cependant, je voulais que les boutons de soumission, les boutons radio et les cases à cocher soient également ignorés, j'ai donc changé le if () en ceci: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, voir mon commentaire sur la réponse d'erikallen. Cela devrait également expliquer contentEditable.
secousse
10
@MaffooClock: vous pouvez être plus concis avec.is(':checkbox,:radio,:submit')
cdmckay
1
@cdmckay: Je ne peux pas croire que je ne l'ai pas écrit de cette façon en premier lieu. Merci d'avoir nettoyé tout ça pour nous tous :)
Matthew Clark
41

Les autres réponses ici ont établi que cela ne peut pas être fait sans liste blanche dans laquelle le retour arrière est autorisé. Cette solution n'est pas idéale car la liste blanche n'est pas aussi simple que les simples zones de texte et les entrées de texte / mot de passe, mais elle se révèle à plusieurs reprises incomplète et doit être mise à jour.

Cependant, puisque le but de supprimer la fonctionnalité de retour arrière est simplement d'empêcher les utilisateurs de perdre accidentellement des données, la solution beforeunload est bonne car la fenêtre contextuelle modale est surprenante - les fenêtres contextuelles modales sont mauvaises lorsqu'elles sont déclenchées dans le cadre d'un flux de travail standard, parce que l'utilisateur s'habitue à les rejeter sans les lire, et ils sont ennuyeux. Dans ce cas, la popup modale n'apparaîtrait que comme une alternative à une action rare et surprenante, et est donc acceptable.

Le problème est qu'un modal onbeforeunload ne doit pas apparaître chaque fois que l'utilisateur s'éloigne de la page (comme en cliquant sur un lien ou en soumettant un formulaire), et nous ne voulons pas commencer à mettre sur liste blanche ou sur liste noire des conditions onbeforeunload spécifiques.

La combinaison idéale de compromis pour une solution généralisée est la suivante: gardez une trace si le retour arrière est pressé, et ne faites apparaître le modal onbeforeunload que si c'est le cas. En d'autres termes:

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

Cela a été testé pour fonctionner dans IE7 +, FireFox, Chrome, Safari et Opera. Déposez simplement cette fonction dans votre global.js et appelez-la depuis n'importe quelle page où vous ne voulez pas que les utilisateurs perdent accidentellement leurs données.

Notez qu'un modal onbeforeunload ne peut être déclenché qu'une seule fois, donc si l'utilisateur appuie à nouveau sur le retour arrière, le modal ne se déclenchera plus.

Notez que cela ne se déclenchera pas lors d'événements de hachage, mais dans ce contexte, vous pouvez utiliser d'autres techniques pour empêcher les utilisateurs de perdre accidentellement leurs données.

Vladimir Kornea
la source
2
Je suis juste allé ajouter cette même solution et j'ai vu ce post en bas de la page LOL. Une différence que j'ai est de définir lastUserInputWasBackspace = false avant la déclaration de retour "Êtes-vous sûr ...", de sorte que vous n'obtiendrez pas la fenêtre contextuelle si vous cliquez sur le bouton de retour après avoir déjà vu la fenêtre contextuelle (c'est donc cohérent avec comportement influencé par le retour arrière).
David Russell
1
@ user2407309 J'ai supprimé mon commentaire (pas une plainte) sur le fait que Firefox ne fonctionne pas avec votre solution. Il y avait un problème avec mon débogueur. Mes excuses pour avoir édité / cassé votre code. Je me rends compte maintenant que j'ai dépassé mes limites (montage) pardonnez-moi. Je suis vraiment désolé et je ne voulais pas me plaindre de votre merveilleuse solution à ce problème. Encore mes excuses. Ce code fonctionne bien. Je pense que c'est la meilleure réponse et je vous en félicite.
Charles Byrne
1
Cette solution a fonctionné sur ma machine locale, mais lorsque je l'ai déplacée, le client (au moins certains d'entre eux) a perdu la fonctionnalité de la moitié de l'application. Je suppose que quelque chose le rejette, mais je n'ai aucune idée de quoi.
Steve
1
@Steve, rare ou non, s'il y a un problème avec la fonction, cette information appartient ici. Je veux juste savoir s'il y a vraiment un problème.
Vladimir Kornea
1
Belle solution, mais malheureusement, si un utilisateur appuie accidentellement deux fois sur la touche de retour arrière, il revient toujours en arrière. (au moins sur firefox)
Remco de Zwart
26

Une solution plus élégante / concise:

$(document).on('keydown',function(e){
  var $target = $(e.target||e.srcElement);
  if(e.keyCode == 8 && !$target.is('input,[contenteditable="true"],textarea'))
  {
    e.preventDefault();
  }
})
Darwayne
la source
1
C'est beaucoup plus concis et d'après ce que je peux dire, cela fonctionne aussi bien. Pourquoi est-ce que la réponse la plus populaire a toutes ces vérifications pour les types d'entrées, et semble plus compliquée? Est-ce plus fiable?
Nearpoint
1
La réponse la plus populaire a été la première à répondre à la question, d'où les votes élevés.
Darwayne
4
lorsque les champs en lecture seule sont concentrés, la suppression revient toujours dans le chrome
Will D
16

Modification de la réponse d'erikkallen pour répondre à différents types d'entrée

J'ai trouvé qu'un utilisateur entreprenant pouvait appuyer sur la touche de retour arrière sur une case à cocher ou un bouton radio dans une vaine tentative pour la désactiver et à la place, il reculerait et perdrait toutes ses données.

Ce changement devrait résoudre ce problème.

Nouvelle modification pour traiter les divs modifiables du contenu

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

Exemple
Pour tester créer 2 fichiers.

starthere.htm - ouvrez-le d'abord pour avoir un endroit où revenir

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

test.htm - Cela permet de revenir en arrière lorsque vous appuyez sur la touche de retour arrière alors que la case à cocher ou la soumission a le focus (obtenue par tabulation). Remplacez par mon code pour corriger.

<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
la source
Quel navigateur avez-vous vu revenir en arrière appuyer sur la radio | case à cocher | soumettre -> fonction de retour? Je n'ai pas vu un navigateur faire ça ..
theetoolman
Internet Explorer 8 et Chrome
Biff MaGriff
2
J'ai essayé un certain nombre d'autres solutions dans ce fil, mais celle-ci fonctionnait bien dans toutes mes situations et avait le code le plus propre et le plus facile à comprendre. Je vous remercie.
Ezward
Avez-vous essayé @ Darwayne, je suis curieux de savoir pourquoi celui-ci est si court et c'est plus complexe, mais les deux semblent fonctionner de la même manière pour moi
Nearpoint
Est-ce que cela fonctionne sur les liens? J'ai une application ASP.Net avec un bouton d'image pour supprimer un élément. C'est la seule chose sur laquelle cela n'a pas fonctionné jusqu'à présent ...
Steve
8

Sur la base des commentaires, il semble que vous souhaitiez empêcher les gens de perdre des informations dans les formulaires, s'ils appuient sur la touche de retour arrière pour supprimer mais que le champ n'est pas ciblé.

Dans ce cas, vous souhaitez consulter le gestionnaire d' événements onunload . Stack Overflow l'utilise - si vous essayez de quitter une page lorsque vous avez commencé à écrire une réponse, un avertissement s'affiche.

Chèvre mécontente
la source
4
désolé, c'était un commentaire grossier. Ce que je veux dire, c'est que l'utilisateur ne veut probablement pas être réprimandé pour avoir fait quelque chose qu'il ne savait même pas faux. Pourquoi ne pas simplement manger la clé en silence avec un onkeydown? Le but n'est pas d'empêcher complètement l'utilisateur de quitter la page, mais de se prémunir contre cette erreur courante. De plus, les boîtes de dialogue contextuelles ne sont ni très efficaces ni utiles. Les utilisateurs ne les lisent pas. Voulez-vous vraiment quitter la page? D'accord! Non, attendez, je ne voulais pas quitter la page .. oups trop tard.
Breton
3
OK alors prenez-le ou laissez-le. Je pense que vous essayez de sur-concevoir un problème qui n'existe pas vraiment, ou du moins n'est pas important. Et d'après mon expérience, seuls les utilisateurs expérimentés cliquent sur "OK" dans des boîtes de dialogue inconnues sans les lire correctement. ;)
DisgruntledGoat
3
Êtes-vous et Breton la même personne? Quoi qu'il en soit, vous vous êtes tiré une balle dans le pied - l'article dit "la réponse par défaut est Annuler", donc quand vous verrez la boîte de dialogue sur la sortie de la page, ils vont appuyer sur "Annuler" et donc ne pas quitter la page. Cependant, il convient de noter que les options de Chrome dans cette boîte de dialogue sont "Quitter cette page" et "Rester sur cette page", qui sont très claires.
DisgruntledGoat
1
Non, ce n'est pas moi, mais j'ai déjà rencontré ce lien auparavant. Je pense que les commentaires sont hilarants. "Quoi!? Les gens ignorent les boîtes de dialogue modales? Nous devons trouver un moyen de les rendre encore PLUS persistants et ennuyeux!". Explique vraiment beaucoup de choses sur les logiciels Microsoft.
Breton
3
@Disgruntled: Non, je ne suis pas breton, et le but de l'article n'est pas "Le choix par défaut est ..." mais "les utilisateurs ne lisent rien."
erikkallen
7

Arrêtez de naviguer ce code fonctionne!

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

Mais pour ne pas restreindre les champs de texte mais d'autres

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

Pour l'empêcher pour un champ spécifique, utilisez simplement

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

Se référant à celui-ci ci-dessous!

Empêcher BACKSPACE de revenir en arrière avec jQuery (comme la page d'accueil de Google)

Syed Ehtsham Abbas
la source
7

La plupart des réponses sont en jquery. Vous pouvez le faire parfaitement en Javascript pur, simple et sans bibliothèque requise. Cet article était un bon point de départ pour moi, mais comme keyIdentifier est obsolète, je voulais que ce code soit plus sécurisé, j'ai donc ajouté || e.keyCode == 8 à l'instruction if. De plus, le code ne fonctionnait pas bien sur Firefox, j'ai donc ajouté return false; et maintenant ça marche parfaitement bien. C'est ici:

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

Ce code fonctionne très bien car,

  1. Il est en pur javascript (aucune bibliothèque requise).
  2. Non seulement il vérifie la touche enfoncée, mais il confirme si l'action est vraiment une action "retour" du navigateur.
  3. Avec ce qui précède, l'utilisateur peut taper et supprimer du texte des zones de texte d'entrée sur la page Web sans aucun problème tout en empêchant l'action du bouton de retour.
  4. Il est court, propre, rapide et droit au but.

Vous pouvez ajouter console.log (e); pour vos besoins de test, et appuyez sur F12 en chrome, allez dans l'onglet "console" et appuyez sur "backspace" sur la page et regardez à l'intérieur pour voir quelles valeurs sont retournées, puis vous pouvez cibler tous ces paramètres pour améliorer encore le code ci-dessus pour répondre à vos besoins.

Tarik
la source
6

Combiner les solutions proposées par "thetoolman" && "Biff MaGriff"

le code suivant semble fonctionner correctement dans 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
la source
L'ajout d'IMAGE peut également être utile.
mrswadge
je me suis installé sur celui-ci.
Corentin
5

Je ne sais pas pourquoi personne ne vient de répondre à cela - cela semble être une question technique parfaitement raisonnable pour demander si c'est possible.

Non, je ne pense pas qu'il existe un moyen multi-navigateur pour désactiver le bouton de retour arrière. Je sais que ce n'est pas activé par défaut dans FF ces jours-ci.

brabster
la source
3
Moins 1 pour ne pas avoir répondu à la question et pour avoir perdu du temps
Andrew
4

J'ai eu du mal à trouver une réponse non JQUERY. Merci à Stas de m'avoir mis sur la piste.

Chrome: si vous n'avez pas besoin de la prise en charge de plusieurs navigateurs, vous pouvez simplement utiliser une liste noire, plutôt qu'une liste blanche. Cette version JS pure fonctionne dans Chrome, mais pas dans IE. Pas sûr de FF.

Dans Chrome (version 36, mi-2014), les pressions de touches qui ne se trouvent pas sur une entrée ou un élément modifiable semblent être ciblées <BODY>. Cela permet d'utiliser une liste noire, que je préfère à la liste blanche. IE utilise la cible du dernier clic - il peut donc s'agir d'un div ou de toute autre chose. Cela rend cela inutile dans 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: Pour le javascript pur, j'ai trouvé que la réponse de Stas était la meilleure. L'ajout d'une vérification de condition supplémentaire pour contenteditable l'a fait fonctionner pour moi *:

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

* Notez que les IE [edit: et Spartan / TechPreview] ont une "fonctionnalité" qui rend les éléments liés aux tables non modifiables . Si vous cliquez sur l'un de ceux-ci et PUIS appuyez sur retour arrière, il reviendra en arrière. Si vous n'avez pas de modifiables <td>, ce n'est pas un problème.

Josiah
la source
3

Cette solution est similaire à d'autres qui ont été publiées, mais elle utilise une simple liste blanche la rendant facilement personnalisable pour autoriser le retour arrière dans les éléments spécifiés simplement en définissant le sélecteur dans la fonction .is ().

Je l'utilise sous cette forme pour empêcher le retour arrière sur les pages de revenir en arrière:

$(document).on("keydown", function (e) {
    if (e.which === 8 && !$(e.target).is("input:not([readonly]), textarea")) {
        e.preventDefault();
    }
});
Aucun
la source
2
Lorsque l'utilisateur utilise contenteditable, cela le désactiverait. Donc, vous voudrez peut-être ajouter le contenteditable = true dans la liste blanche
Miguel
3

Pour élaborer un peu sur l' excellente réponse de @ erikkallen , voici une fonction qui permet tous les types d'entrée basés sur le clavier, y compris ceux introduits 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();
    }
});
Gingi
la source
Merci, j'utilise cette réponse! Avez-vous trouvé des problèmes avec ces solutions jusqu'à présent?
Nearpoint
1
Je recommande de déplacer les déclarations INPUTTYPES, TEXTRE hors de la fonction afin qu'elles ne soient pas recalculées à chaque événement de keydown.
thetoolman
3

JavaScript - manière jQuery:

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

Javascript - la manière native, qui fonctionne pour moi:

<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
la source
@MichaelPotter C'était bien pour le cas d'utilisation du mien, il y a longtemps. N'hésitez pas à contribuer en améliorant / modifiant ma réponse. THX!
Vladimir Djuricic
2

J'ai eu quelques problèmes avec la solution acceptée et le plugin Select2.js; Je n'ai pas pu supprimer les caractères dans la zone modifiable car l'action de suppression était empêchée. C'était ma solution:

//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 crée un Span avec un attribut "contentEditable" qui est défini sur true pour la zone de liste modifiable modifiable qu'il contient. J'ai ajouté du code pour prendre en compte les étendues tagName et les différents attributs. Cela a résolu tous mes problèmes.

Edit: Si vous n'utilisez pas le plugin Select2 combobox pour jquery, alors cette solution peut ne pas être nécessaire par vous, et la solution acceptée pourrait être meilleure.

Pytry
la source
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
la source
2
Vous ne devez pas utiliser return false. e.preventDefault est recommandé. Vous arrêtez également la propagation de l'événement pour chaque clé et pas seulement pour le retour arrière. Enfin, keyCode 13 est enter et la question portait sur la prévention de la navigation arrière avec retour arrière, mais cela empêcherait enter de soumettre le formulaire ou d'effectuer d'autres actions.
Aucun
1

Ce code résout le problème dans tous les navigateurs:

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
la source
1
Je trouve que ce code ne fonctionne pas comme prévu en raison du d.tagname étant DIVou TD.
Biff MaGriff,
Le code de Haseeb Akhtar fonctionne parfaitement dans Chrome et Firefox, mais surprise !! pas dans IE6-9 Des suggestions?
Martin Andersen
1

Moyen le plus simple d'empêcher la navigation en appuyant sur la touche de retour arrière

$(document).keydown(function () {
    if (event.keyCode == 8) {
        if (event.target.nodeName == 'BODY') {
            event.preventDefault();
        }
    }
});
Mohammed Irfan Mayan
la source
Empêche la navigation en appuyant sur backspcae, et en même temps autorise le retour arrière avec tous les contrôles d'entrée
Mohammed Irfan Mayan
Et ne manquez pas la première ligne .. $ (document) .keydown (function () {
Mohammed Irfan Mayan
3
cela désactivera le bouton de retour à l'intérieur des zones de texte et des entrées
nodrog
1

En utilisant Dojo toolkit 1.7, cela fonctionne dans 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
la source
1

Avez-vous essayé la solution très simple consistant simplement à ajouter l'attribut suivant à votre champ de texte en lecture seule:

onkeydown = "return false;"

Cela empêchera le navigateur de revenir dans l'historique lorsque la touche Retour arrière est enfoncée dans un champ de texte en lecture seule. Peut-être que je manque votre véritable intention, mais il semble que ce serait la solution la plus simple à votre problème.

B-Dog
la source
1

Une solution beaucoup plus soignée -

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

Alternativement, vous ne pouvez vérifier que si

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

Version javascript pur, qui fonctionne dans tous les navigateurs:

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

Bien sûr, vous pouvez utiliser "INPUT, TEXTAREA" et utiliser "if (! Regex.test (elements))" alors. Le premier a bien fonctionné pour moi.

Stanislav Parkhomenko
la source
1

Performance?

J'étais inquiet pour les performances et j'ai fait un violon: http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/

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

J'ai analysé les méthodes les plus prometteuses que j'ai trouvées dans ce fil. Il s'avère qu'ils étaient tous très rapides et ne posent probablement pas de problème de "lenteur" lors de la frappe. La méthode la plus lente que j'ai examinée était d'environ 125 ms pour 10 000 appels dans IE8. Soit 0,0125 ms par course.

J'ai trouvé que les méthodes publiées par Codenepal et Robin Maben étaient les plus rapides ~ 0,001 ms (IE8) mais méfiez-vous des différentes sémantiques.

C'est peut-être un soulagement pour quelqu'un qui introduit ce type de fonctionnalité à son code.

gangrené
la source
1

Réponse erikkallen modifiée:

$(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
la source
1
Réponse parfaite. La solution que j'ai obtenue des autres n'a pas fonctionné dans Firefox, mais celle-ci fonctionnait parfaitement dans les trois (Firefox, IE et Crome) sans aucun problème. Merci Prozi.
Nikhil Dinesh
1

Cette solution a très bien fonctionné lors des tests.

J'ai ajouté du code pour gérer certains champs de saisie non balisés avec entrée et pour les intégrer dans une application Oracle PL / SQL qui génère un formulaire d'entrée pour mon travail.

Mes deux centimes":

 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
la source
1

J'ai créé un projet NPM avec une version propre de l'actuel accepté (d'erikkallen)

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

Il utilise essentiellement les mêmes principes mais:

  • Pas de dépendance
  • Prise en charge de contenteditable
  • Base de code plus lisible / maintenable
  • Sera pris en charge car il sera utilisé en production par mon entreprise
  • Licence 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);
};
Sébastien Lorber
la source
1

Voici ma réécriture de la réponse la plus votée. J'ai essayé de vérifier element.value! == indéfini (car certains éléments comme peuvent ne pas avoir d'attribut html mais peuvent avoir une propriété de valeur javascript quelque part sur la chaîne du prototype), mais cela ne fonctionnait pas très bien et avait beaucoup de cas marginaux. Il ne semble pas y avoir de bon moyen de pérenniser cela, donc une liste blanche semble la meilleure option.

Cela enregistre l'élément à la fin de la phase de bulle d'événement, donc si vous souhaitez gérer le retour arrière d'une manière personnalisée, vous pouvez le faire dans d'autres gestionnaires.

Cela vérifie également l'instance de HTMLTextAreElement car on pourrait théoriquement avoir un composant Web qui en hérite.

Cela ne vérifie pas contentEditable (à combiner avec d'autres réponses).

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
la source
0

Sitepoint: désactiver le retour pour Javascript

event.stopPropagation()et event.preventDefault()ne rien faire dans IE. J'ai dû envoyer le retour event.keyCode == 11(je viens de choisir quelque chose) au lieu de simplement dire "if not = 8, run the event"pour le faire fonctionner. event.returnValue = falsefonctionne également.

À M
la source
0

Une autre méthode utilisant 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
la source
Veuillez noter que cela ne fonctionne pas si des contrôles (zone de texte) ont été ajoutés dynamiquement.
CodeNepal
0

J'utilise cela dans mon code depuis un certain temps maintenant. J'écris des tests en ligne pour les étudiants et suis tombé sur le problème lorsque les étudiants appuyaient sur le retour arrière pendant leur test et cela les ramènerait à l'écran de connexion. Frustrant! Cela fonctionne sur FF à coup sûr.

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