Jak mogę zapobiec cofnięciu się klawisza Backspace?


275

W IE mogę to zrobić za pomocą (okropnie niestandardowego, ale działającego) jQuery

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

Ale czy można to zrobić w sposób, który działa w przeglądarce Firefox lub w przeglądarce, aby uzyskać bonus?

Dla przypomnienia:

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

nic nie robi.

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

rozwiązuje problem, ale sprawia, że ​​klawisz Backspace nie nadaje się do użytku na stronie, co jest nawet gorsze niż oryginalne zachowanie.

EDYCJA: Powodem tego jest to, że nie tworzę prostej strony internetowej, ale dużą aplikację. Bardzo denerwujące jest tracenie 10 minut pracy tylko dlatego, że nacisnąłeś backspace w niewłaściwym miejscu. Stosunek zapobiegania błędom do irytujących użytkowników powinien być znacznie powyżej 1000/1, uniemożliwiając cofanie się klawisza Backspace.

EDIT2: Ja nie próbuje zapobiec nawigację historię, tylko wypadków.

EDIT3: @brentonstrines komentarz (przeniesiony tutaj, ponieważ pytanie jest tak popularne): Jest to długoterminowa „poprawka”, ale możesz rzucić swoje poparcie za błędem Chromium, aby zmienić to zachowanie w zestawie internetowym


137
Ponieważ klawisz Backspace jest przeciążony. Być może tego nie zauważyłeś, ale prawdopodobnie używasz go cały czas do usuwania liter, które właśnie wpisałeś w polu tekstowym. Niektórzy z moich klientów mieli problem z tym, że strona się cofnęła, więc jest to przydatna informacja. Nikt oprócz was, klaunów, nie wie, że backspace powinien wrócić na stronę. To coś, o czym nigdy nie wiedziałem, a wręcz wrogie zachowanie przeglądarki. Myślę, że wszystkie strony powinny wyłączyć to zachowanie.
Breton

80
Dlaczego ludzie myślą, że to dziwne? Używanie backspace do nawigacji to naprawdę głupi skrót! jest tak wiele pól tekstowych, że użytkownicy mogą chcieć usunąć tekst - wyobraź sobie, że masz długą odpowiedź SO, przełączasz się do innego okna, aby coś sprawdzić, a potem wracasz i źle klikasz obszar edycji, naciśnij backspace, aby usunąć słowo i nagle przeglądarka wraca o jedną stronę i potencjalnie straciłeś wszystko, co właśnie napisałeś.
Peter Boughton

57
Dlaczego chcę to zrobić? Nie tworzę strony internetowej, ale aplikację internetową. Niektóre pola wejściowe są tylko do odczytu, w takim przypadku wyglądają na edytowalne, ale jeśli naciśniesz backspace, opuścisz stronę. Stosunek naciśnięć backspace zamierzających nawigować wstecz do naciśnięć backspace próbujących coś skasować jest prawdopodobnie znacznie mniejszy niż 1 / 1000.
erikkallen

42
Pytanie brzmi, jak to zrobić, a nie twoja opinia, czy to dobry pomysł, czy nie. Bez znajomości szczegółów projektu Twoje opinie są bez znaczenia. Mój klient specjalnie poprosił o takie zachowanie w jednym z moich projektów i prawdziwą odpowiedź, a nie „Dlaczego miałbyś chcieć to zrobić?” byłoby pomocne.
Brak,

7
Jest to długoterminowa „poprawka”, ale możesz rzucić wsparcie za błędem Chromium, aby zmienić to zachowanie w pakiecie internetowym: code.google.com/p/chromium/issues/detail?id=144832
brentonstrine

Odpowiedzi:


335

Ten kod rozwiązuje problem, przynajmniej w IE i Firefox (nie testowałem żadnego innego, ale daję mu rozsądną szansę na działanie, jeśli problem istnieje nawet w innych przeglądarkach).

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

6
Łamie pola hasła.
Hemlock

7
Jak stwierdził Hemlock - sprawdź d.type.toUpperCase() === 'PASSWORD'również. Poza tym wygląda dobrze
stevendesu,

17
Ponieważ już używasz jQueryif( $(d).is( ":input" ) )...
Paul Alexander

23
Bani, że musi to być biała lista, a nie możliwość umieszczenia na czarnej liście funkcji „wstecz”. Możesz dodać tutaj czek d.isContentEditable.
iono

3
Stworzyłem projekt NPM z czystą wersją obecnie akceptowanej odpowiedzi: github.com/slorber/backspace-disabler (obsługuje także edytowalne treści i nie ma zależności)
Sebastien Lorber

62

Ten kod działa we wszystkich przeglądarkach i połyka klawisz Backspace, gdy nie ma go w elemencie formularza lub jeśli element formularza jest wyłączony | tylko do odczytu. Jest również wydajny, co jest ważne, gdy wykonuje się na każdym wpisanym kluczu.

$(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
Przetestuj mój przykład, możesz odpowiednio zaktualizować kod.
Biff MaGriff 21.11.11

10
Wolę to niż rozwiązanie @ erikkallen, ponieważ jest czystsze. Chciałem jednak zignorować przyciski przesyłania, przyciski opcji i pola wyboru, dlatego zmieniłem if () na: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, zobacz mój komentarz do odpowiedzi Erikallena. To powinno również uwzględniać contentEditable.
wstrząs

10
@MaffooClock: możesz być bardziej zwięzły z.is(':checkbox,:radio,:submit')
cdmckay

1
@cdmckay: Nie mogę uwierzyć, że nie napisałem tego w ten sposób. Dzięki za sprzątanie tego dla nas wszystkich :)
Matthew Clark

41

Inne odpowiedzi tutaj wykazały, że nie można tego zrobić bez elementów białej listy, w których dozwolony jest Backspace. To rozwiązanie nie jest idealne, ponieważ biała lista nie jest tak prosta jak zwykłe pola tekstowe i wprowadzanie tekstu / hasła, ale wielokrotnie okazuje się, że jest niekompletna i wymaga aktualizacji.

Ponieważ jednak tłumienie funkcji backspace ma jedynie na celu zapobieżenie przypadkowej utracie danych przez użytkowników, rozwiązanie beforeunload jest dobre, ponieważ wyskakujące okno modalne jest zaskakujące - wyskakujące okna modalne są złe, gdy są uruchamiane w ramach standardowego przepływu pracy, ponieważ użytkownik przyzwyczaja się do ich odrzucania bez ich czytania i są denerwujące. W tym przypadku wyskakujące okno modalne pojawiłoby się jedynie jako alternatywa dla rzadkiej i zaskakującej akcji, a zatem jest akceptowalne.

Problem polega na tym, że modal onbeforeunload nie może się pojawiać, ilekroć użytkownik opuści stronę (na przykład po kliknięciu linku lub przesłaniu formularza), i nie chcemy zaczynać na białej liście lub na czarnej liście określonych warunków onbeforeunload.

Idealna kombinacja kompromisów dla uogólnionego rozwiązania jest następująca: śledź, czy wciśnięty jest backspace, i wyświetlaj modal onbeforeunload, jeśli tak jest. Innymi słowy:

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

Zostało to przetestowane pod kątem działania w IE7 +, FireFox, Chrome, Safari i Opera. Po prostu upuść tę funkcję w pliku global.js i wywołaj ją z dowolnej strony, na której nie chcesz, aby użytkownicy przypadkowo utracili swoje dane.

Zauważ, że modal onbeforeunload można uruchomić tylko raz, więc jeśli użytkownik ponownie naciśnie backspace, modal nie uruchomi się ponownie.

Pamiętaj, że nie spowoduje to uruchomienia zdarzeń haszowania, jednak w tym kontekście możesz użyć innych technik, aby zapobiec przypadkowej utracie danych przez użytkowników.


2
Po prostu poszedłem dodać to samo rozwiązanie i zobaczyłem ten post na dole strony LOL. Jedną różnicą, którą mam, jest ustawienie lastUserInputWasBackspace = false przed zwrotem „Czy jesteś pewien ...”, więc nie pojawi się wyskakujące okienko, jeśli klikniesz przycisk Wstecz po zobaczeniu wyskakującego okienka (więc jest to zgodne z zachowanie zależne od backspace).
David Russell

1
@ user2407309 Usunąłem swój komentarz (nie reklamację) na temat tego, że Firefox nie działa z Twoim rozwiązaniem. Wystąpił problem z moim debuggerem. Przepraszamy za edycję / złamanie kodu. Teraz zdaję sobie sprawę, że przekroczyłem swoje granice (edycja), wybacz mi. Naprawdę przepraszam i nie miałem na myśli żadnych skarg na twoje wspaniałe rozwiązanie tego problemu. Jeszcze raz przepraszam. Ten kod działa dobrze. Uważam, że to najlepsza odpowiedź i pochwalam za to.
Charles Byrne,

1
To rozwiązanie działało na moim komputerze lokalnym, ale kiedy go przeniosłem, klient (przynajmniej niektóre z nich) utracił funkcjonalność połowy aplikacji. Wydaje mi się, że coś to odrzuca, ale nie mam pojęcia co.
Steve

1
@ Steve, rzadkie lub nie, jeśli występuje problem z funkcją, informacja ta należy tutaj. Chcę tylko wiedzieć, czy naprawdę jest problem.
Vladimir Kornea

1
Dobre rozwiązanie, ale niestety, jeśli użytkownik przypadkowo naciśnie klawisz Backspace dwa razy, nadal nawiguje do tyłu. (przynajmniej na firefox)
Remco de Zwart

26

Bardziej eleganckie / zwięzłe rozwiązanie:

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

1
Jest to o wiele bardziej zwięzłe i z tego, co mogę powiedzieć, działa równie dobrze. Dlaczego najpopularniejsza odpowiedź ma wszystkie rodzaje danych wejściowych i wydaje się bardziej skomplikowana? Czy to jest bardziej niezawodne?
Nearpoint

1
Najpopularniejszą odpowiedzią była pierwsza, która odpowiedziała na pytanie, a więc wysokie głosy.
Darwayne

4
gdy pola tylko do odczytu są skoncentrowane, usuwanie nadal nawiguje z powrotem w chromie
Czy D

16

Modyfikacja odpowiedzi erikkallen w celu uwzględnienia różnych typów danych wejściowych

Przekonałem się, że przedsiębiorczy użytkownik może naciskać klawisz Backspace na polu wyboru lub przycisk radiowy w próżnej próbie wyczyszczenia go, a zamiast tego nawigowałby wstecz i tracił wszystkie swoje dane.

Ta zmiana powinna rozwiązać ten problem.

Nowa edycja do obsługi edytowalnych elementów div

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

Przykład
Aby przetestować, utwórz 2 pliki.

starthere.htm - otwórz ten pierwszy, aby mieć miejsce, do którego można wrócić

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

test.htm - Nawiguje do tyłu po naciśnięciu klawisza Backspace, gdy pole wyboru lub przesłanie jest aktywne (osiągane poprzez tabulacja). Zamień na mój kod, aby to naprawić.

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

W jakiej przeglądarce widziałeś naciśnięcie klawisza Backspace w radiu | pole wyboru | prześlij -> funkcja powrotu? Nie widziałem, żeby przeglądarka to robiła.
thetoolman

Internet Explorer 8 i Chrome
Biff MaGriff

2
Próbowałem wielu innych rozwiązań w tym wątku, ale ten działał dobrze we wszystkich moich sytuacjach i miał najczystszy, najłatwiejszy do zrozumienia kod. Dziękuję Ci.
Ezward

Czy próbowałeś @Darwayne, jestem ciekawy, dlaczego ten jest tak krótki, a to jest bardziej złożone, ale oba wydają się działać dla mnie tak samo
Nearpoint

Czy to działa na linkach? Mam aplikację ASP.Net z przyciskiem obrazu do usunięcia elementu. To jedyna rzecz, na którą do tej pory nie działało ...
Steve

8

Na podstawie komentarzy wydaje się, że chcesz powstrzymać ludzi przed utratą informacji w formularzach, jeśli naciśnie klawisz Backspace, aby je usunąć, ale pole nie jest aktywne.

W takim przypadku chcesz spojrzeć na moduł obsługi zdarzeń onunload . Stos przepełnienia stosuje go - jeśli spróbujesz opuścić stronę, gdy zacząłeś pisać odpowiedź, pojawi się ostrzeżenie.


4
przepraszam, to był niegrzeczny komentarz. Chodzi mi o to, że użytkownik prawdopodobnie nie chce być krytykowany za robienie czegoś, o czym nawet nie wiedzieli, że jest źle. Dlaczego nie po prostu w ciszy zjeść klucz w trybie onkeydown? Celem nie jest całkowite powstrzymanie użytkownika od opuszczenia strony, ale ochrona przed tym powszechnym błędem. Ponadto wyskakujące okna dialogowe nie są zbyt skuteczne ani przydatne. Użytkownicy ich nie czytają. Czy na pewno chcesz opuścić stronę? W porządku! Nie czekaj, czekaj, nie chciałem opuszczać strony. Ups za późno.
Breton

3
OK, a następnie weź to lub zostaw. Myślę, że próbujesz przepracować problem, który tak naprawdę nie istnieje, a przynajmniej nie jest ważny. Z mojego doświadczenia wynika, że ​​tylko zaawansowani użytkownicy klikają „OK” w nieznanych oknach dialogowych bez ich prawidłowego czytania. ;)
DisgruntledGoat

3
Czy ty i Breton jesteście tą samą osobą? W każdym razie strzeliłeś sobie w stopę - artykuł mówi „domyślną odpowiedzią jest Anuluj”, więc kiedy zobaczysz okno dialogowe opuszczania strony, będą naciskać „Anuluj” i dlatego nie opuszczą strony. Chociaż należy zauważyć, że opcje Chrome w tym oknie dialogowym to „Opuść tę stronę” i „Pozostań na tej stronie”, które są bardzo jasne.
DisgruntledGoat

1
Nie, on nie jest mną, ale już wcześniej spotkałem ten link. Myślę, że komentarze są przezabawne. „Co !? ludzie ignorują modalne okna dialogowe? Musimy znaleźć sposób, aby uczynić je jeszcze bardziej upartymi i denerwującymi!”. Naprawdę wiele wyjaśnia na temat oprogramowania Microsoft.
Breton

3
@Disgruntled: Nie, nie jestem Bretonem, a artykuł nie brzmi „Domyślny wybór to…”, ale „użytkownicy nic nie czytają”.
erikkallen

7

Przestań nawigować po tym kodzie działa!

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

Ale żeby nie ograniczać pól tekstowych, ale innych

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

Aby temu zapobiec, po prostu użyj

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

Odnosząc się do tego poniżej!

Zapobiegaj cofaniu się BACKSPACE z powrotem za pomocą jQuery (jak na stronie głównej Google)


7

Większość odpowiedzi znajduje się w jquery. Możesz to zrobić doskonale w czystym JavaScript, prosty i bez biblioteki. Ten artykuł był dla mnie dobrym punktem wyjścia, ale ponieważ keyIdentifier jest przestarzały, chciałem, aby ten kod był bardziej bezpieczny, dlatego dodałem || e.keyCode == 8 do instrukcji if. Ponadto kod nie działał dobrze w przeglądarce Firefox, więc dodałem return false; a teraz działa idealnie dobrze. Oto on:

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

Ten kod działa świetnie, ponieważ

  1. Jest w czystym javascript (nie wymaga biblioteki).
  2. Nie tylko sprawdza naciśnięty klawisz, ale potwierdza, czy akcja jest tak naprawdę działaniem „wstecznym” przeglądarki.
  3. Wraz z powyższym użytkownik może bez problemu wpisywać i usuwać tekst z pól tekstowych na stronie internetowej, jednocześnie zapobiegając działaniu przycisku Wstecz.
  4. Jest krótki, czysty, szybki i od razu do rzeczy.

Możesz dodać console.log (e); dla celów testowych i wciśnij F12 w chrome, przejdź do zakładki „konsola” i wciśnij „backspace” na stronie i zajrzyj do środka, aby zobaczyć, jakie wartości są zwracane, a następnie możesz kierować wszystkie te parametry, aby dodatkowo ulepszyć kod powyżej w zależności od potrzeb.


6

Łączenie rozwiązań „thetoolman” i& „Biff MaGriff”

poniższy kod wydaje się działać poprawnie w 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();
    });
}); 

Przydatne może być również dodanie OBRAZU.
mrswadge,

zdecydowałem się na ten.
Corentin

5

Nie jestem pewien, dlaczego nikt nie odpowiedział na to pytanie - wydaje się całkowicie rozsądnym pytaniem technicznym, aby zapytać, czy to możliwe.

Nie, nie sądzę, aby istniał sposób umożliwiający przeglądanie stron w celu wyłączenia przycisku Backspace. Wiem, że obecnie nie jest domyślnie włączona w FF.


3
Minus 1 za brak odpowiedzi na pytanie i marnowanie czasu
Andrew

3

To rozwiązanie jest podobne do innych, które zostały opublikowane, ale wykorzystuje prostą białą listę, dzięki czemu można go łatwo dostosować, aby umożliwić cofanie w określonych elementach, po prostu ustawiając selektor w funkcji .is ().

Używam go w tym formularzu, aby zapobiec cofaniu się backspace na stronach:

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

2
Gdy użytkownik korzysta z contenteditable, spowoduje to wyłączenie. Możesz więc dodać contenteditable = true do białej listy
Miguel

3

Aby nieco rozwinąć doskonałą odpowiedź @ erikkallen , oto funkcja, która pozwala na wszystkie typy wprowadzania oparte na klawiaturze, w tym te wprowadzone w 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();
    }
});

Dzięki, używam tej odpowiedzi! Czy do tej pory znalazłeś jakieś problemy z tymi rozwiązaniami?
Nearpoint

1
Polecam usunięcie deklaracji INPUTTYPES, TEXTRE z funkcji, aby nie były przeliczane przy każdym zdarzeniu keydown.
thetoolman

3

JavaScript - sposób jQuery:

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

JavaScript - natywny sposób, który działa dla mnie:

<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 Dawno temu było w porządku dla mojego przypadku użycia. Prosimy nieść swój wkład, poprawiając / zmieniając moją odpowiedź. Dzięki!
Vladimir Djuricic

3

Trudno mi było znaleźć odpowiedź inną niż JQUERY. Dzięki Staśowi za umieszczenie mnie na torze.

Chrom: jeśli nie potrzebujesz obsługi wielu przeglądarek, możesz po prostu użyć czarnej listy zamiast białej listy. Ta czysta wersja JS działa w Chrome, ale nie w IE. Nie jestem pewien co do FF.

W Chrome (wer. 36, połowa 2014 r.) Wydaje się, że są one naciskane na klawisze, których nie ma na danych wejściowych ani na elementach, które można zadowolić <BODY>. Umożliwia to korzystanie z czarnej listy, którą wolę od białej listy. IE używa celu ostatniego kliknięcia - może to być div lub cokolwiek innego. To sprawia, że ​​jest to bezużyteczne w 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: Dla czystego javascript, odpowiedź Stasia była najlepsza. Dodanie jeszcze jednego warunku sprawdzania zawartości sprawiło, że zadziałało to dla mnie *:

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

* Należy pamiętać, że IE [edit: i Spartan / TechPreview] mają „funkcję”, która sprawia, że elementy związane z tabelą są nieedytowalne . Jeśli klikniesz jeden z nich, a następnie Naciśniesz backspace, przejdzie on wstecz. Jeśli nie masz edytowalnych <td>plików, nie stanowi to problemu.


2

Miałem pewne problemy z zaakceptowanym rozwiązaniem i wtyczką Select2.js; Nie byłem w stanie usunąć znaków z edytowalnego pola, ponieważ akcja usuwania była uniemożliwiona. To było moje rozwiązanie:

//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 tworzy zakres z atrybutem „contentEditable”, który jest ustawiony na true dla edytowalnego pola kombi w nim. Dodałem kod, aby uwzględnić zakres tagName i inny atrybut. To rozwiązało wszystkie moje problemy.

Edycja: Jeśli nie używasz wtyczki Select2 combobox do jquery, to rozwiązanie może nie być potrzebne, a zaakceptowane rozwiązanie może być lepsze.


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
Nie powinieneś używać return false. e.preventDefault jest zalecany. Zatrzymujesz także propagację zdarzenia dla każdego klucza, a nie tylko backspace. Wreszcie, keyCode 13 jest wprowadzony, a pytanie dotyczyło uniemożliwienia cofnięcia nawigacji za pomocą backspace, ale uniemożliwiłoby to enterowi przesłanie formularza lub wykonanie innych działań.
Brak,

1

Ten kod rozwiązuje problem we wszystkich przeglądarkach:

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
Uważam, że ten kod nie działa zgodnie z oczekiwaniami z powodu istnienia zmiennej d.tagname DIVlub TD.
Biff MaGriff,

Kod z Haseeb Akhtar działa idealnie w Chrome i Firefox, ale niespodzianka !! nie w IE6-9 Jakieś sugestie?
Martin Andersen

1

Najprostszy sposób, aby zapobiec nawigacji po naciśnięciu klawisza Backspace

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

Uniemożliwia nawigację po naciśnięciu backspcae, a jednocześnie umożliwia cofanie się we wszystkich kontrolkach wprowadzania
Mohammed Irfan Mayan

I nie przegap pierwszego wiersza .. $ (dokument) .keydown (function () {
Mohammed Irfan Mayan

3
spowoduje to wyłączenie przycisku wewnątrz obszarów tekstowych i danych wejściowych
nodrog

1

Przy użyciu pakietu narzędzi Dojo 1.7 działa to w 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

Czy wypróbowałeś bardzo proste rozwiązanie polegające na dodaniu następującego atrybutu do pola tekstowego tylko do odczytu:

onkeydown = "return false;"

Zapobiegnie to cofnięciu się przeglądarki do historii po naciśnięciu klawisza Backspace w polu tekstowym tylko do odczytu. Może brakuje mi twojej prawdziwej intencji, ale wydaje się, że byłoby to najprostsze rozwiązanie twojego problemu.


1

Znacznie lepsze rozwiązanie -

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

Alternatywnie możesz tylko sprawdzić, czy

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

1

Wersja czystego javascript, która działa we wszystkich przeglądarkach:

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

Oczywiście możesz użyć „INPUT, TEXTAREA” i użyć „if (! Regex.test (elements))”. Pierwszy działał dobrze dla mnie.


1

Występ?

Martwiłem się wydajnością i zrobiłem skrzypce: http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/

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

Przeanalizowałem najbardziej obiecujące metody, które znalazłem w tym wątku. Okazuje się, że wszystkie były bardzo szybkie i najprawdopodobniej nie powodują problemu pod względem „powolności” podczas pisania. Najwolniejsza metoda, jaką obejrzałem, to około 125 ms dla 10.000 wywołań w IE8. Co wynosi 0,0125 ms na skok.

Odkryłem, że metody opublikowane przez Codenepala i Robina Mabena są najszybsze ~ 0,001 ms (IE8), ale uważaj na inną semantykę.

Być może jest to ulga dla kogoś, kto wprowadza tego rodzaju funkcje do swojego kodu.


1

Zmodyfikowana odpowiedź erikkallen:

$(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
Idealna odpowiedź. Rozwiązanie, które otrzymałem od innych, nie zadziałało w firefoxie, ale to doskonale działało we wszystkich trzech (Firefox, IE i crome) bez żadnego problemu. Dzięki Prozi.
Nikhil Dinesh

1

To rozwiązanie działało bardzo dobrze podczas testowania.

Dodałem trochę kodu do obsługi niektórych pól wejściowych nieoznaczonych danymi wejściowymi i do integracji z aplikacją Oracle PL / SQL, która generuje formularz wejściowy dla mojego zadania.

Moje dwa centy":

 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

Stworzyłem projekt NPM z czystą wersją aktualnie akceptowanego (erikkallen)

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

Wykorzystuje w zasadzie te same zasady, ale:

  • Bez zależności
  • Wsparcie dla zadowolonych
  • Bardziej czytelna / łatwa w obsłudze baza kodu
  • Będzie wspierany, ponieważ będzie wykorzystywany w produkcji przez moją firmę
  • Licencja 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

Oto moje przepisane na najczęściej głosowaną odpowiedź. Próbowałem sprawdzić element.value! == undefined (ponieważ niektóre elementy, takie jak mogą nie mieć atrybutu html, ale mogą mieć właściwość wartości javascript gdzieś w łańcuchu prototypów), jednak nie działało to zbyt dobrze i miało wiele przypadków krawędzi. Wydaje się, że nie ma dobrego sposobu na zabezpieczenie tego na przyszłość, więc biała lista wydaje się najlepszą opcją.

Rejestruje to element na końcu fazy bąbelkowej zdarzenia, więc jeśli chcesz obsługiwać Backspace w dowolny niestandardowy sposób, możesz to zrobić w innych programach obsługi.

Sprawdza to również wystąpienie HTMLTextAreElement, ponieważ teoretycznie można mieć komponent internetowy, który dziedziczy po nim.

Nie sprawdza to contentEditable (w połączeniu z innymi odpowiedziami).

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

Punkt serwisowy: wyłącz ponownie dla Javascript

event.stopPropagation()i event.preventDefault()nie rób nic w IE. Musiałem jednak wysłać zwrot event.keyCode == 11(właśnie coś wybrałem) zamiast po prostu powiedzieć, "if not = 8, run the event"że to działa. event.returnValue = falsedziała również.


0

Inna metoda wykorzystująca 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>

Uwaga: to nie działa, jeśli formanty (pole tekstowe) zostały dodane dynamicznie.
CodeNepal

0

Używam tego w moim kodzie już od jakiegoś czasu. Piszę testy online dla studentów i napotkałem problem, gdy uczniowie naciskali klawisz Backspace podczas testu i zabrałoby ich to z powrotem do ekranu logowania. Denerwujący! Na pewno działa na FF.

document.onkeypress = Backspace;
function Backspace(event) {
    if (event.keyCode == 8) {
        if (document.activeElement.tagName == "INPUT") {
            return true;
        } else {
            return false;
        }
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.