如何防止退格键向后导航?

Posted

技术标签:

【中文标题】如何防止退格键向后导航?【英文标题】:How can I prevent the backspace key from navigating back? 【发布时间】:2010-12-02 11:40:25 【问题描述】:

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

EDIT2:我不是试图阻止历史导航,只是意外。

EDIT3:@brentonstrines 评论(因为这个问题很受欢迎,所以移到这里):这是一个长期的“修复”,但你可以支持Chromium bug to change this behavior in webkit

【问题讨论】:

因为退格键过载。您可能没有注意到它,但您可能一直使用它来擦除您刚​​刚在文本字段中输入的字母。我的一些客户遇到了导致页面返回的问题,所以这是有用的信息。除了你们这些小丑之外,没有人知道退格键应该返回一个页面。这是我从来不知道的事情,对于浏览器来说,这是完全的敌对行为。我认为所有页面都应该禁用这种行为。 为什么人们觉得这很奇怪?使用退格键导航是一个非常愚蠢的快捷方式!有很多文本字段,用户可能想要从中删除文本 - 想象一下,有一个很长的 SO 答案,切换到另一个窗口检查某些内容,然后您返回并错误单击编辑区域,按退格键删除一个单词,然后突然,浏览器返回一个页面,你可能会丢失刚刚写的所有内容。 我为什么要这样做?我不是在创建一个网站,而是一个 Web 应用程序。某些输入字段是只读的,在这种情况下它们看起来是可编辑的,但如果您按退格键,则会离开页面。打算向后导航的退格键与尝试擦除某些内容的退格键的比率可能远小于 1 / 1000。 问题是如何做到这一点,而不是你对它是否是一个好主意的看法。在不了解项目细节的情况下,您的意见毫无意义。我的客户已经特别要求我的一个项目的这种行为和一个真正的答案,而不是“你为什么要这样做?”会有帮助的。 这是一个长期的“修复”,但您可以支持 Chromium 错误以更改 webkit 中的这种行为:code.google.com/p/chromium/issues/detail?id=144832 【参考方案1】:

不知道为什么没有人回答这个问题 - 似乎是一个完全合理的技术问题来询问这是否可能。

不,我认为没有跨浏览器的方法可以禁用退格按钮。我知道这些天在 FF 中默认没有启用它。

【讨论】:

因不回答实际问题而浪费时间而减 1【参考方案2】:

根据 cmets,您似乎希望阻止人们在表单中丢失信息,如果他们按退格键删除但字段没有聚焦。

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

【讨论】:

对不起,这是一个粗鲁的评论。我的意思是,用户可能不想因为做了他们甚至不知道是错误的事情而受到指责。为什么不用 onkeydown 默默地吃掉钥匙?目标不是完全阻止用户离开页面,而是防止这种常见错误。此外,弹出式对话不是很有效或有用。用户不阅读它们。您确定要离开该页面吗?好的!别等了,我不想离开页面..哎呀太晚了。 OK 然后拿走或离开。我认为您正在尝试过度设计一个实际上并不存在或至少不重要的问题。根据我的经验,只有高级用户会在不熟悉的对话框上单击“确定”而没有正确阅读它们。 ;) 你和布列塔尼是同一个人吗?无论如何,你有点自责 - 文章说“默认答案是取消”,所以当看到有关离开页面的对话框时,他们会按“取消”,因此离开这页纸。不过需要注意的是,Chrome 在该对话框上的选项是“离开此页面”和“留在此页面上”,非常清晰。 不,他不是我,但我以前遇到过那个链接。我觉得cmets很搞笑。 “什么!?人们忽略了模式对话框?我们必须找到一种方法让它们更加持久和烦人!”。真正解释了很多关于微软软件的知识。 @Disgruntled:不,我不是布列塔尼人,这篇文章的重点不是“默认选择是……”而是“用户什么都不读”。【参考方案3】:

这段代码解决了这个问题,至少在 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;
        
    
);

【讨论】:

仅添加了对文本输入的检查,如果您专注于按钮,则退格键正在工作。 正如 Hemlock 所说 - 检查d.type.toUpperCase() === 'PASSWORD'。否则看起来不错 既然你已经在使用 jQuery if( $(d).is( ":input" ) )... 这很糟糕,这必须是一个白名单,而不是能够将“返回”功能列入黑名单。您可能需要在此处添加对 d.isContentEditable 的检查。 我创建了一个 NPM 项目,其中包含当前接受的答案的干净版本:github.com/slorber/backspace-disabler(它还支持 contenteditables 并且没有依赖项)【参考方案4】:

这段代码解决了所有浏览器的问题:

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

  

【讨论】:

我发现由于 d.tagname 为 DIVTD,此代码无法按预期工作。 Haseeb Akhtar 的代码在 Chrome 和 Firefox 中完美运行,但令人惊讶!不在 IE6-9 有什么建议吗?【参考方案5】:
    document.onkeydown = function (e)     
        e.stopPropagation();
        if ((e.keyCode==8  ||  e.keyCode==13) &&
            (e.target.tagName != "TEXTAREA") && 
            (e.target.tagName != "INPUT"))  
            return false;
        
    ;

【讨论】:

你不应该使用 return false。推荐使用 e.preventDefault。此外,您正在停止传播每个键的事件,而不仅仅是退格键。最后,keyCode 13 是 enter,问题是关于防止使用退格键进行后退导航,但这会阻止 enter 提交表单或执行其他操作。【参考方案6】:

另一种使用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>

【讨论】:

请注意,如果控件(文本框)已被动态添加,这将不起作用。【参考方案7】:

修改 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();
    );

示例 测试make 2个文件。

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>

【讨论】:

您在哪个浏览器中看到了在收音机|复选框|提交 -> 后退功能上按退格键?我还没有看到浏览器这样做.. Internet Explorer 8 和 Chrome 我在这个线程中尝试了许多其他解决方案,但这个解决方案在我的所有情况下都运行良好,并且拥有最干净、最容易理解的代码。谢谢。 你试过@Darwayne吗?我很想知道为什么那个这么短而且这个更复杂,但对我来说两者似乎都一样 这对链接有效吗?我有一个带有图像按钮的 ASP.Net 应用程序来删除项目。这是迄今为止唯一没有奏效的事情......【参考方案8】:

Sitepoint: Disable back for Javascript

event.stopPropagation()event.preventDefault() 在 IE 中什么都不做。不过,我必须发送返回 event.keyCode == 11(我刚刚选择了一些东西)而不是仅仅说 "if not = 8, run the event" 才能让它工作。 event.returnValue = false 也可以。

【讨论】:

【参考方案9】:

此代码适用于所有浏览器,当不在表单元素上或表单元素被禁用|只读时,会吞下退格键。它也很高效,这在对输入的每个键执行时很重要。

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

【讨论】:

请测试我的示例,您可能希望相应地更新您的代码。 我更喜欢 @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 ) @thetoolman,请参阅我对 erikallen 回答的评论。这也应该考虑到contentEditable @MaffooClock:.is(':checkbox,:radio,:submit') 可以更简洁 @cdmckay:我不敢相信我一开始不是那样写的。感谢您为我们所有人清理它:)【参考方案10】:

结合“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();
    );
); 

【讨论】:

添加 IMAGE 也可能有用。 我选择了这个。【参考方案11】:

防止按退格键导航的最简单方法

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

【讨论】:

按退格键阻止导航,同时在所有输入控件中允许退格键 不要错过第一行..$(document).keydown(function () 这将禁用文本区域和输入中的后退按钮【参考方案12】:

此解决方案与已发布的其他解决方案类似,但它使用了一个简单的白名单,使其易于定制,只需在 .is() 函数中设置选择器即可在指定元素中允许退格。

我以这种形式使用它来防止页面上的退格键向后导航:

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

【讨论】:

当用户使用 contenteditable 时,它​​会被禁用。所以你可能想在白名单中添加 contenteditable=true【参考方案13】:

我在接受的解决方案和 Select2.js 插件方面遇到了一些问题;由于删除操作被阻止,我无法删除可编辑框中的字符。这是我的解决方案:

//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 创建一个具有“contentEditable”属性的 Span,该属性为其中的可编辑组合框设置为 true。我添加了代码来说明 spans tagName 和不同的属性。这解决了我所有的问题。

编辑:如果您没有使用用于 jquery 的 Select2 组合框插件,那么您可能不需要此解决方案,并且接受的解决方案可能会更好。

【讨论】:

【参考方案14】:

使用 Dojo 工具包 1.7,这适用于 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());
);

【讨论】:

【参考方案15】:

我在我的代码中使用它已经有一段时间了。我为学生编写了在线测试,当学生在测试期间按退格键时遇到了问题,这会让他们回到登录屏幕。令人沮丧!它肯定适用于FF。

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

【讨论】:

【参考方案16】:

您是否尝试过将以下属性添加到只读文本字段的非常简单的解决方案:

onkeydown="返回假;"

当在只读文本字段中按下退格键时,这将防止浏览器返回历史记录。也许我错过了您的真实意图,但似乎这将是您问题的最简单解决方案。

【讨论】:

【参考方案17】:

更简洁的解决方案 -

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

或者,您只能检查是否

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

【讨论】:

【参考方案18】:

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

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

【讨论】:

这更加简洁,据我所知也同样有效。为什么最受欢迎的答案会检查所有输入类型,而且看起来更复杂?它更可靠吗? 最受欢迎的答案是第一个回答问题的人,因此获得了高票。 当只读字段聚焦时,删除仍会在 chrome 中导航回【参考方案19】:

纯javascript版本,适用于所有浏览器:

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;
    
  

当然你可以使用“INPUT, TEXTAREA”然后使用“if (!regex.test(elements))”。第一个对我来说很好。

【讨论】:

【参考方案20】:

性能?

我担心性能问题并做了一个小提琴:http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/

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

我已经分析了我在这个帖子中找到的最有前途的方法。事实证明,它们都非常快,并且很可能不会在打字时造成“迟钝”问题。 我看到的最慢的方法是在 IE8 中进行 10.000 次调用大约需要 125 毫秒。即每笔划 0.0125 毫秒。

我发现 Codenepal 和 Robin Maben 发布的方法最快约 0.001 毫秒 (IE8),但要注意不同的语义。

对于将这种功能引入他的代码的人来说,这也许是一种解脱。

【讨论】:

【参考方案21】:

稍微详细说明@erikkallen 的excellent answer,这里有一个函数允许所有基于键盘的输入类型,包括those introduced in 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();
    
);

【讨论】:

谢谢,我正在使用这个答案!到目前为止,您是否发现此解决方案有任何问题? 我建议将 INPUTTYPES、TEXTRE 声明移出函数,这样它们就不会在每个 keydown 事件上重新计算。【参考方案22】:

这里的其他答案已经确定,如果不将允许 Backspace 的元素列入白名单,则无法做到这一点。这种解决方案并不理想,因为白名单不像文本区域和文本/密码输入那么简单,而是反复发现不完整,需要更新。

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

问题在于,当用户离开页面时(例如单击链接或提交表单时),onbeforeunload 模式不得弹出,并且我们不想开始将特定的 onbeforeunload 条件列入白名单或黑名单。

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

function confirmBackspaceNavigations () 
    // http://***.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

已经过测试,可以在 IE7+、FireFox、Chrome、Safari 和 Opera 中使用。只需将此函数放入您的 global.js 并从您不希望用户意外丢失数据的任何页面调用它。

注意,onbeforeunload modal 只能触发一次,所以如果用户再次按下退格键,modal 将不会再次触发。

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

【讨论】:

我刚刚添加了相同的解决方案,并在页面底部看到了这篇文章 LOL。我的一个区别是在 return "Are you sure..." 语句之前设置 lastUserInputWasBackspace = false ,因此如果您在看到弹出窗口后碰巧单击后退按钮,则不会收到弹出窗口(因此它与非退格影响的行为)。 @user2407309 我已经删除了关于 Firefox 无法使用您的解决方案的评论(不是投诉)。我的调试器有问题。对于编辑/破坏您的代码,我深表歉意。我现在意识到我越界了(编辑)原谅我。我真的很抱歉,我无意抱怨你对这个问题的精彩解决方案。再次,我很抱歉。这段代码运行良好。我相信这是最好的答案,我对此表示赞赏。 这个解决方案在我的本地机器上工作,但是当我把它移过来时,客户端(至少其中一些)失去了一半应用程序的功能。我猜有些东西在拒绝它,但我不知道是什么。 @Steve,无论是否罕见,如果功能有问题,该信息属于这里。我只是想知道是否真的有问题。 不错的解决方案,但不幸的是,如果用户不小心按了两次退格键,它仍然会返回。 (至少在 Firefox 上)【参考方案23】:

我很难找到非 JQUERY 的答案。感谢 Stas 让我走上正轨。

Chrome:如果您不需要跨浏览器支持,您可以只使用黑名单,而不是白名单。这个纯 JS 版本在 Chrome 中工作,但在 IE 中不工作。不确定FF。

在 Chrome(版本 36,2014 年中)中,不在 input 或 contenteditable 元素上的按键似乎针对&lt;BODY&gt;。这使得使用黑名单成为可能,我更喜欢将其列入白名单。 IE 使用最后一次点击目标 - 所以它可能是一个 div 或其他任何东西。这使得这在 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();
        
    
  

跨浏览器:对于纯 javascript,我发现 Stas 的答案是最好的。为 contenteditable 添加一项条件检查使其对我有用*:

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;
            
        
    

*请注意,IE [编辑:和 Spartan/TechPreview] 有一个“功能”,它使 table-related elements uneditable。如果您单击其中一个然后按退格键,它将导航回来。如果您没有可编辑的&lt;td&gt;s,这不是问题。

【讨论】:

【参考方案24】:

修改后的 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;
    
);

【讨论】:

完美答案。我从其他人那里得到的解决方案在 Firefox 中不起作用,但这个解决方案在所有三个(Firefox、IE 和 crom)中都完美地工作,没有任何问题。谢谢 Prozi。【参考方案25】:

为我工作

<script type="text/javascript">


 if (typeof window.event != 'undefined')
    document.onkeydown = function()
    
        if (event.srcElement.tagName.toUpperCase() != 'INPUT')
            return (event.keyCode != 8);
    
else
    document.onkeypress = function(e)
    
        if (e.target.nodeName.toUpperCase() != 'INPUT')
            return (e.keyCode != 8);
    

</script>

【讨论】:

【参考方案26】:

JavaScript - jQuery 方式:

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

Javascript - 适合我的原生方式:

<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 很久以前我的用例没问题。请随时通过改进/更改我的答案来做出贡献。谢谢!【参考方案27】:

这个解决方案在测试时效果很好。

我确实添加了一些代码来处理一些未标记输入的输入字段,并集成到一个 Oracle PL/SQL 应用程序中,该应用程序为我的工作生成一个输入表单。

我的“两分钱”:

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

【讨论】:

【参考方案28】:

对于任何有兴趣的人,我已经将thetoolman 的(加上@MaffooClock/@cdmckay 的cmets)和@Vladimir Kornea 的上述想法结合在一起的jQuery 插件。

用法:

//# Disable backspace on .disabled/.readOnly fields for the whole document
$(document).disableBackspaceNavigation();

//# Disable backspace on .disabled/.readOnly fields under FORMs
$('FORM').disableBackspaceNavigation();

//# Disable backspace on .disabled/.readOnly fields under #myForm
$('#myForm').disableBackspaceNavigation();

//# Disable backspace on .disabled/.readOnly fields for the whole document with confirmation
$(document).disableBackspaceNavigation(true);

//# Disable backspace on .disabled/.readOnly fields for the whole document with all options
$(document).disableBackspaceNavigation(
    confirm: true,
    confirmString: "Are you sure you want to navigate away from this page?",
    excludeSelector: "input, select, textarea, [contenteditable='true']",
    includeSelector: ":checkbox, :radio, :submit"
);

插件:

//# Disables backspace initiated navigation, optionally with a confirm dialog
//#     From: https://***.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back
$.fn.disableBackspaceNavigation = function (vOptions) 
    var bBackspaceWasPressed = false,
        o = $.extend(
            confirm: (vOptions === true),   //# If the caller passed in `true` rather than an Object, default .confirm accordingly,
            confirmString: "Are you sure you want to leave this page?",
            excludeSelector: "input, select, textarea, [contenteditable='true']",
            includeSelector: ":checkbox, :radio, :submit"
        , vOptions)
    ;

    //# If we are supposed to use the bConfirmDialog, hook the beforeunload event
    if (o.confirm) 
        $(window).on('beforeunload', function () 
            if (bBackspaceWasPressed) 
                bBackspaceWasPressed = false;
                return o.confirmString;
            
        );
    

    //# Traverse the passed elements, then return them to the caller (enables chainability)
    return this.each(function () 
        //# Disable backspace on disabled/readonly fields
        $(this).bind("keydown keypress", function (e) 
            var $target = $(e.target /*|| e.srcElement*/);

            //# If the backspace was pressed
            if (e.which === 8 /*|| e.keyCode === 8*/) 
                bBackspaceWasPressed = true;

                //# If we are not using the bConfirmDialog and this is not a typeable input (or a non-typeable input, or is .disabled or is .readOnly), .preventDefault
                if (!o.confirm && (
                    !$target.is(o.excludeSelector) ||
                    $target.is(o.includeSelector) ||
                    e.target.disabled ||
                    e.target.readOnly
                )) 
                    e.preventDefault();
                
            
        );
    );
; //# $.fn.disableBackspaceNavigation

【讨论】:

【参考方案29】:

我创建了一个 NPM 项目,其中包含当前接受的(erikkallen)的干净版本

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

它使用基本相同的原理,但是:

无依赖性 支持 contenteditable 更具可读性/可维护性的代码库 将得到支持,因为它将被我的公司用于生产 MIT 许可证
var Backspace = 8;

// See http://***.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://***.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);
;

【讨论】:

【参考方案30】:

这是我对最高投票答案的重写。我尝试检查 element.value!==undefined (因为某些元素可能没有 html 属性,但可能在原型链的某处具有 javascript value 属性),但是效果不佳并且有很多边缘情况。似乎没有一个很好的方法来证明这一点,所以白名单似乎是最好的选择。

这会在事件冒泡阶段结束时注册元素,因此如果您想以任何自定义方式处理 Backspace,您可以在其他处理程序中这样做。

这也会检查 instanceof HTMLTextAreElement,因为理论上可以有一个继承自它的 Web 组件。

这不会检查 contentEditable(与其他答案结合)。

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

【讨论】:

以上是关于如何防止退格键向后导航?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止用户使用浏览器的后退按钮或退格键访问上一个 jsp 页面 [重复]

防止退格按钮导航回上一个 XPage

如何使用jQuery捕获退格键? [复制]

readonly 退格键 网页后退

如何将加速键赋予键盘退格键

如何将退格键更改为 '\b'?