如何防止按下退格键后返回上一页?

290

在IE中,我可以使用(非常不标准但有效的)jQuery实现此操作

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

但是有没有可能以一种适用于Firefox的方式或者实现跨浏览器的方式呢?

记录一下:

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

不做任何事情。

$(document).keydown(function(e) { if (e.keyCode == 8) e.preventDefault(); });
解决了问题,但造成了页面上不能使用退格键的问题,这甚至比原来的行为更糟糕。
编辑: 我这么做的原因是我不是在创建一个简单的网页,而是在创建一个大型应用程序。仅仅因为你在错误的位置按了一下退格键就会丢失10分钟的工作时间,这实在是太让人恼火了。避免错误与打扰用户的比例应该远高于1000/1,通过禁止退格键导航回去来防止这种情况。
编辑2:我并不想阻止历史记录导航,只是想要防止意外发生。
编辑3:@brentonstrines评论(将其移到此处,因为问题如此流行):这是一个长期的“修复”方法,但您可以支持Chromium bug以更改webkit中的此行为

142
由于退格键功能过载,你可能没有注意到,但你可能经常使用它来删除刚刚在文本框中键入的字母。我的一些客户因为这个问题而感到困扰,导致页面返回,所以这是有用的信息。除了你们这些小丑之外,没人知道退格键应该返回上一页。这是我从未知道的事情,对于浏览器来说,这是完全敌对的行为。我认为所有页面都应该禁用这种行为。 - Breton
83
为什么人们认为这很奇怪?使用退格键进行导航是一个非常愚蠢的快捷方式!有很多文本字段用户可能想要删除文本——想象一下有一个很长的stackoverflow答案,在切换到另一个窗口查看东西后,你回来时误点了编辑区域,按下退格键删除一个单词,突然浏览器返回上一页,你可能会丢失你刚刚写的所有内容。 - Peter Boughton
59
为什么我想这样做呢?我不是在创建一个网站而是一个网络应用程序。一些输入字段是只读的,看起来像可编辑的,但如果您按退格键,您将离开该页面。想要导航回去的退格键次数与试图删除某些内容的退格键次数的比率可能远小于1/1000。 - erikkallen
43
问题是如何做到这一点,而不是你对此是否是个好主意的看法。如果不知道该项目的详细信息,你的意见是没有意义的。我的客户特别要求在我的一个项目中实现这种行为,一个真正的答案而不是“你为什么要这样做?”会更有帮助。 - None
7
这是一个长期的“修复”计划,但你可以支持Chromium bug来更改webkit中的这种行为:http://code.google.com/p/chromium/issues/detail?id=144832 - brentonstrine
显示剩余13条评论
33个回答

340

这段代码解决了问题,至少在IE和Firefox中(我没有测试其他浏览器,但如果问题在其他浏览器中存在,我认为它也有合理的机会工作)。

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

7
正如Hemlock所说,也要检查d.type.toUpperCase() === 'PASSWORD'。否则看起来不错。 - stevendesu
17
既然您已经在使用jQuery,那么 if( $(d).is( ":input" ) )... 可以这样写。 - Paul Alexander
1
@PaulAlexander 使用 if( $(d).is( ":input" ) ) 是不行的,因为如果用户选择了下拉框输入,然后按下退格键,仍会发生不良行为。 - intrepidis
23
很糟糕,这必须是一个白名单,而不能黑名单“返回”功能。你可能需要在这里添加一个d.isContentEditable的检查。 - iono
4
我用现在被普遍接受的答案创建了一个 NPM 项目:https://github.com/slorber/backspace-disabler (它还支持 contenteditable,并且没有任何依赖)。 - Sebastien Lorber
显示剩余11条评论

66

这段代码适用于所有浏览器,并且可以在不在表单元素上时吞噬退格键,或者当表单元素被禁用|只读时。它还很高效,在每次按键时执行非常重要。

$(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
请测试我的示例,您可能需要相应更新您的代码。 - Biff MaGriff
10
我更喜欢这个解决方案而不是 @erikkallen 提供的,因为它更简洁。但是,我希望“提交”按钮、单选按钮和复选框也被忽略,所以我将if()改成了这样: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,看一下我对erikallen答案的评论。这也应该考虑到contentEditable - tomsseisums
10
“@MaffooClock: 你可以使用.is(':checkbox,:radio,:submit')更加简洁。” - cdmckay
1
@cdmckay:我简直不敢相信我一开始没有这样写。感谢您为我们所有人整理了它 :) - Matthew Clark
我认为这个答案没有rx检查,但是@VladimirKornea的回答是最好的、最适应性强的答案,因为现在几乎任何东西都可以被编辑。 - cmbarbu

42

其他回答已经说明了,如果不允许在特定元素中使用退格键,则无法完成此操作。这种解决方案并不理想,因为白名单不仅仅是文本区域和文本/密码输入框那么简单,而且常常发现它是不完整的,需要不断更新。

然而,由于抑制退格键功能的目的仅仅是为了防止用户意外丢失数据,所以beforeunload解决方案是一个好选择,因为模态弹出窗口是出人意料的。当模态弹出窗口作为标准工作流程的一部分被触发时,它们会让用户习惯于在不阅读它们的情况下解除它们,这很烦人。在这种情况下,模态弹出窗口仅会出现作为一种罕见和令人惊讶的动作的替代品,因此是可以接受的。

问题是,当用户离开页面(例如单击链接或提交表单)时,onbeforeunload模态必须不会弹出,我们不想开始白名单或黑名单指定的onbeforeunload条件。

通用解决方案的理想权衡组合如下:跟踪是否按下退格键,并仅在按下退格键时弹出onbeforeunload模态。换句话说:

function confirmBackspaceNavigations () {
    // https://dev59.com/ynI_5IYBdhLWcg3wK_zE#22949859
    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

这已经在IE7+、FireFox、Chrome、Safari和Opera中测试过。只需将此函数放入您的global.js文件中,在任何您不想让用户意外丢失数据的页面中调用它即可。

请注意,onbeforeunload模态框只能被触发一次,因此如果用户再次按下退格键,模态框将不会再次触发。

请注意,这不会触发hashchange事件,但是在那种情况下,您可以使用其他技术来防止用户意外丢失数据。


2
我刚想添加同样的解决方案,结果看到了这篇帖子在页面底部哈哈。我的一个不同之处是在返回“你确定…”语句之前将lastUserInputWasBackspace = false设置为false,这样如果你已经看过弹出窗口后又点击了返回按钮,就不会再次弹出窗口(这样与非退格键影响行为一致)。 - David Russell
2
@user2407309 我已经删除了我的评论(不是抱怨),关于Firefox与您的解决方案不兼容的问题。这是我的调试器出了问题。对于编辑/破坏您的代码,我深感抱歉。我现在意识到我越界了(编辑),请原谅我。我真的很抱歉,我没有对您解决这个问题的好方法提出任何抱怨。再次,我的道歉。这段代码运行良好。我相信这是最好的答案,我为您的解决方案表示赞扬。 - Charles Byrne
1
这个解决方案在我的本地机器上运行良好,但是当我将其移植到客户端时(至少其中一些客户端),应用程序的一半功能失效了。我猜测有些东西正在拒绝它,但我不知道是什么。 - Steve
1
@Steve,无论罕见与否,如果函数存在问题,那么这个信息应该在这里提出。我只是想知道是否真的存在问题。 - Val Kornea
2
不错的解决方案,但不幸的是,如果用户意外地按两次退格键,它仍然会后退。(至少在火狐浏览器上) - Remco de Zwart
显示剩余7条评论

28

一种更加优雅/简洁的解决方案:

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

1
这个更加精简,据我所知同样有效。为什么最受欢迎的答案要检查输入类型,并且看起来更加复杂?这样做是否更可靠? - Nearpoint
1
最受欢迎的答案是第一个回答问题的,因此获得了高票数。 - Darwayne
4
当在Chrome中聚焦只读字段时,即使删除键被按下,仍会导航回上一页。 - Will D

16

修改 erikkallen 的答案以解决不同输入类型的问题

我发现有些用户可能会在复选框或单选按钮上按退格键,试图清除选择,结果导致他们返回上一页并且失去所有数据。

这个修改应该可以解决这个问题。

新的编辑来解决可编辑 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();
    });
例子
为了测试,请制作两个文件。

starthere.htm - 首先打开此文件,以便您有一个返回的地方。

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

test.htm - 当复选框或提交按钮聚焦(通过标签切换实现)时,按退格键将导航后退。请替换为我的代码以解决此问题。

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

你在哪个浏览器上看到按下退格键会回到上一页的功能?我从未见过有浏览器这样做过。 - thetoolman
Internet Explorer 8和Chrome - Biff MaGriff
2
我在这个帖子中尝试了许多其他解决方案,但这一个在所有情况下都表现良好,并且具有最干净、最易于理解的代码。谢谢。 - Ezward
你试过@Darwayne吗?我很好奇为什么那个如此简短而这个更复杂,但对我来说两者都一样有效。 - Nearpoint
这个适用于链接吗?我有一个ASP.Net应用程序,其中包含一个图像按钮以删除项目。到目前为止,这是唯一没有起作用的事情... - Steve

10
大多数答案都是基于jquery的。你可以用纯JavaScript完美地实现,简单而且不需要库。这篇文章是我开始的好起点,但由于keyIdentifier已经被弃用,我想让这段代码更加安全,所以我在if语句中添加了||e.keyCode==8。另外,这段代码在Firefox上运行不太好,所以我添加了return false;现在它运行得非常完美。以下是代码:
<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>

这段代码非常好,因为:
  1. 它是纯JavaScript的(不需要任何库)。
  2. 它不仅检查按键,还确认操作是否真正是浏览器的“后退”操作。
  3. 除了上述功能外,用户可以在网页上的输入文本框中键入和删除文本,而无需担心后退按钮的操作。
  4. 它简短、干净、快速且直接明了。

您可以添加console.log(e);以进行测试,并在Chrome中按F12,在“控制台”选项卡中单击页面上的“退格键”,然后查看返回的值,然后您可以针对所有这些参数进一步增强上面的代码以满足您的需求。


9

根据评论,您希望防止用户在表单中误删除信息,但如果该字段没有焦点,则按下退格键。

在这种情况下,您需要查看 onunload 事件处理程序。 Stack Overflow使用它-如果您在编写答案时尝试离开页面,它会弹出警告。


4
抱歉之前的评论有些粗鲁。我的意思是,该用户可能不想因为做了他们不知道错误的事情而受到责备。为什么不只是在按下按键时悄悄地吃掉这个按键呢?目标不是完全防止用户离开页面,而是防止这种常见错误。此外,弹出对话框并不是非常有效或有用的,因为用户不会读它们。“您确定要离开此页吗?”“好的!”“等等等等,我不想离开这个页面。。。”(哎呀,太迟了) - Breton
3
好的,接受或放弃吧。我认为你试图过度设计一个并不存在或者至少不重要的问题。而且根据我的经验,只有高级用户才会在没有认真阅读对话框的情况下点击“确定”按钮。;) - DisgruntledGoat
3
你和Breton是同一个人吗?无论如何,你有点自食恶果——文章说“默认答案是取消”,所以当看到关于离开页面的对话框时,他们会按下“取消”按钮,因此不会离开该页面。尽管应该注意到Chrome在该对话框中的选项是“离开此页”和“留在此页”,这些选项非常清楚明了。 - DisgruntledGoat
1
不,他不是我,但我之前遇到过那个链接。我觉得评论很搞笑。“什么!?人们忽略模态对话框?我们必须找到一种方法使它们更加持久和烦人!”这真的很好地解释了微软软件的许多问题。 - Breton
3
@Disgruntled:不,我不是布列塔尼人,而文章的重点也不是“默认选择是……”,而是“用户不阅读任何内容”。 - erikkallen
显示剩余2条评论

7

阻止导航,这段代码有效!

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

但不限制文本字段以外的内容

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

为了防止它在特定领域中出现,只需使用

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

参考下面这个链接!

使用jQuery防止BACKSPACE键导航回退(像Google主页一样)


6

结合“thetoolman”和“Biff MaGriff”提供的解决方案,以下代码在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();
    });
}); 

添加图像可能也会很有用。 - mrswadge
我选择了这个。 - Corentin

4

不确定为什么没有人回答这个问题 - 看起来是一个完全合理的技术问题,询问是否可能。

不,我认为没有一种跨浏览器的方法可以禁用退格键。虽然我知道现在在FF中默认情况下未启用它。


4
未回答实际问题和浪费时间,扣1分。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接