如何使用JavaScript停止浏览器的后退按钮?

246

我正在使用PHP开发一个在线问答应用程序。我想阻止用户在考试期间返回。

我已经尝试了以下脚本,但是它会停止我的计时器。

我该怎么办?

计时器存储在文件cdtimer.js中。

<script type="text/javascript">
    window.history.forward();
    function noBack()
    {
        window.history.forward();
    }
</script>

<body onLoad="noBack();" onpageshow="if (event.persisted) noBack();" onUnload="">
我有一个考试计时器,它从MySQL的值中获取考试的持续时间。计时器会相应地开始,但当我加入代码禁用后退按钮时它就停止了。我的问题是什么?

我有一个考试计时器,它从MySQL的值中获取考试持续时间。计时器按预期开始,但在我添加禁用后退按钮的代码后,它停止了。我的问题是什么?


这种方法会导致闪烁-浏览器实际上会向后导航,然后再返回。您可以尝试使用我的新NPM包来避免这种情况:https://www.npmjs.com/package/use-history-back-trap) - RandomX
40个回答

198

禁用浏览器的返回按钮可能会导致各种问题,因此最好的方法是向用户发出警告:

window.onbeforeunload = function() { return "Your work will be lost."; };

这个页面确实列出了一些方法,你可以尝试禁用后退按钮,但是没有一个是保证可行的:

http://www.irt.org/script/311.htm


你应该在 PHP 代码中检查答案是否已经提交,如果是,则拒绝它。 - Sela Yair
8
值得一提的是,现代浏览器中的情况已经发生了变化:请参见 https://dev59.com/j2Ij5IYBdhLWcg3wwHlr。 - devrobf
它能够工作,但是这也会在所有的菜单按钮上显示警告。当它要切换页面时,它会显示警告。我们能否只将其修复为仅限于后退按钮? - Muhammad Baber Zaman

164

通常覆盖Web浏览器的默认行为是不明智的。出于安全原因,客户端脚本没有足够的特权来执行此操作。

也有一些类似的问题,

不能真正禁用浏览器的后退按钮。但是,您可以使用逻辑进行魔法操作,以防止用户向后导航,从而产生禁用效果。以下是如何实现-请查看以下代码片段。

(function (global) {

    if(typeof (global) === "undefined") {
        throw new Error("window is undefined");
    }

    var _hash = "!";
    var noBackPlease = function () {
        global.location.href += "#";

        // Making sure we have the fruit available for juice (^__^)
        global.setTimeout(function () {
            global.location.href += "!";
        }, 50);
    };

    global.onhashchange = function () {
        if (global.location.hash !== _hash) {
            global.location.hash = _hash;
        }
    };

    global.onload = function () {
        noBackPlease();

        // Disables backspace on page except on input fields and textarea..
        document.body.onkeydown = function (e) {
            var elm = e.target.nodeName.toLowerCase();
            if (e.which === 8 && (elm !== 'input' && elm  !== 'textarea')) {
                e.preventDefault();
            }
            // Stopping the event bubbling up the DOM tree...
            e.stopPropagation();
        };
    }
})(window);

这段纯JavaScript代码可以在大多数浏览器中运行。它也会禁用退格键,但该键仍然可以在input字段和textarea中正常使用。

推荐设置:

将此代码片段放置在单独的脚本中,并将其包含在您需要此行为的页面中。在当前设置中,它将执行DOM的onload事件,这是此代码的理想入口点。

演示!

已在以下浏览器中进行测试和验证:

  • Chrome。
  • Firefox。
  • Internet Explorer (8-11) 和 Edge。
  • Safari。

1
我不明白为什么要使用setTimeout。如果我只是最初将#!附加到位置并删除setTimeout,它仍然可以工作。 - baraber
1
我按照建议创建了一个 .js 文件,并使用以下代码将 js 文件包含在我的代码中:<script src="./javascript/noback.js"></script> 但是我仍然可以通过 Safari 进行后退操作。我错过了什么吗?这个库的添加方式与我使用的其他库相同,所以包含是正确的。 - Tim
1
阻止iPad Air,iOS 8上的返回按钮。 - plugincontainer
1
@rohit416。刚刚测试了一下,演示如下:
  • 与 Google 87.0.4280.66 不兼容
  • 与 Edge 87.0.664.47 不兼容
  • 仍然与 FF 83.0 兼容。在前两个浏览器中,只有在用户在决定点击后退按钮之前对页面采取某些操作(例如单击)时,它才能正常工作。如果用户没有采取任何操作,则脚本将无法正常工作。
- Jeremie
1
可以在桌面版的Chrome 87.0.4280.141上运行,但无法在Android上运行。 - formicini
显示剩余8条评论

162

我遇到了这个问题,需要一个在各种浏览器上都能正确且“好用”的解决方案,其中包括移动Safari(iOS 9发布时)。目前为止没有任何一个解决方案完全正确。我提供以下解决方案(在Internet Explorer 11、Firefox、Chrome和Safari上测试通过):

history.pushState(null, document.title, location.href);
window.addEventListener('popstate', function (event)
{
  history.pushState(null, document.title, location.href);
});

请注意以下内容:

  • history.forward()(我的旧解决方案)在Mobile Safari上不起作用---似乎什么都没做(即,用户仍然可以返回)。history.pushState() 在它们所有的平台上都有效。
  • history.pushState() 的第三个参数是一个url。那些传递像'no-back-button''pagename'这样的字符串的解决方案似乎工作正常,直到您尝试刷新/重新加载页面为止,在这种情况下,当浏览器尝试定位一个带有该URL的页面时,将生成“找不到页面”错误。(当在页面上时,浏览器也可能将该字符串包含在地址栏中,这很丑陋。)应使用location.href来获取URL。
  • history.pushState() 的第二个参数是一个title。在网络上搜索大多数地方都说它被“不使用”,而这里的所有解决方案都使用null。但是,在至少Mobile Safari中,这会将页面的URL放入用户可以访问的历史记录下拉菜单中。但是,当它正常添加一个页面访问条目时,它会输入它的标题,这是更可取的。因此,将document.title传递给它会产生相同的行为。

5
这是正确的答案。在Chrome、IE 11、Firefox和Edge上完美运行。 - Concept211
5
这应该是被接受的答案,它跨平台并且运行良好。 - calbertts
3
现代浏览器的完美解决方案。我结合了@Rohit416的答案,只使用条件 typeof (history.pushState) === "function" 就可以支持旧版浏览器,并且运行流畅。 - Miklos Krivan
5
在Chrome 79.0.3945.130中,这对我不起作用。我完全按照上述方法实施,可以通过单击“返回”按钮返回。当我长按返回按钮并选择历史记录中的任何项时,确实被阻止了。但是,快速点击返回按钮会立即将我带回到前一页。 - gene b.
3
在Chrome 99上不起作用,直到我点击页面内部(可能是激活window.focus())。但在Firefox上运行良好。有人有解决方案吗? - HarsiddhDave
显示剩余11条评论

81
<script>
    window.location.hash = "no-back-button";

    // Again because Google Chrome doesn't insert
    // the first hash into the history
    window.location.hash = "Again-No-back-button"; 

    window.onhashchange = function(){
        window.location.hash = "no-back-button";
    }
</script>

4
太聪明了!我使用这个方法来防止用户在 web 应用程序中误触返回键(例如,在禁用/只读字段中按下退格键),而在这种情况下,前进/后退功能实际上并没有什么意义。经过确认,它可以禁用回退和前进功能(尽管不能禁用按钮本身),包括上下文菜单选项。在 IE8 到 IE11、Chrome 和 FF 中验证通过。 - nothingisnecessary
2
这个可以运行,但会清除所有输入在文本框中的数据。有没有可能防止清除? - Somnium
7
它在火狐上可用,但在谷歌浏览器上不行(版本为36.0.1985.143)。 - baraber
这对我有用。我用要停留在的页面的哈希替换了“no-back-button”。 - Abhishek
2
这对我不起作用。我正在使用Windows 10上的Chrome版本55。我将脚本放在多个位置(头部开始,主体结束等),但我仍然可以使用后退按钮返回到上一页。 - Victor Stoddard
显示剩余4条评论

42

为限制浏览器后退事件:

window.history.pushState(null, "", window.location.href);
window.onpopstate = function () {
    window.history.pushState(null, "", window.location.href);
};

2
这在Chrome上运行得很好!为什么人们不投票,因为这是最佳答案? - Tarık Seyceri
2
我刚在以下浏览器上使用Windows 10操作系统进行了测试(效果很好): Chrome版本74.0.3729.108(官方版本)(64位) Chrome金丝雀版本76.0.3780.0(官方版本)金丝雀(32位) Chromium版本66.0.3355.0(开发者版本)(64位) Firefox 66.0.3(64位) EDGE IE 11 Safari 5.1.7 - Tarık Seyceri
2
@TarıkSeyceri 因为这仅适用于支持历史记录 API 的浏览器,且页面实际上正在使用历史记录 API 来管理状态。 - givanse
2
在Chrome 75版本之后不再工作。请参见:https://support.google.com/chrome/thread/8721521?hl=en - gene b.

35

如何阻止返回功能:

history.pushState(null, null, location.href);
window.onpopstate = function () {
  history.go(1);
};


23
虽然这可能是一个有效的答案,但通过解释代码是如何工作的,你可以更有可能帮助他人。仅有代码的答案往往会得到较少的正面关注,并且不如其他答案有用。 - Aurora0001
已在Chrome、Firefox、IE和Edge上进行过测试,运行良好。你拯救了我。 - Felix Htoo
已在Chrome 91上测试,完美运行。如果您按照@Aurora0001所述解释一下发生了什么,那会更好。好的答案得到了低投票。 - umekalu
您可以在此处找到有关这段代码片段的解释:https://medium.com/codex/angular-guards-disabling-browsers-back-button-for-specific-url-fdf05d9fe155#4f13 - Vasileios Kagklis

33

这段代码将禁用支持HTML5 History API的现代浏览器的后退按钮。在正常情况下,按下后退按钮会回到上一页。如果使用history.pushState(),则会向当前页面添加额外的子步骤。它的工作方式是,如果您使用history.pushState()三次,然后开始按下后退按钮,则前三次它将在这些子步骤中导航回去,然后第四次将返回到上一页。

如果将此行为与popstate事件上的事件侦听器结合起来,您可以基本上设置一个子状态的无限循环。因此,您加载页面,推送一个子状态,然后点击后退按钮,它将弹出一个子状态并推送另一个子状态,因此,如果再次按下后退按钮,它将永远不会用完子状态。如果您认为有必要禁用后退按钮,可以通过这种方式实现。

history.pushState(null, null, 'no-back-button');
window.addEventListener('popstate', function(event) {
  history.pushState(null, null, 'no-back-button');
});

3
在任何浏览器上,在进行此操作后,尝试刷新/重新加载页面,您将遇到“页面未找到”错误,因为它试图查找名为“no-back-button”的页面... (浏览器也可能在地址栏中显示“no-back-button”,这看起来很丑。)公平地说,这不是唯一受此影响的解决方案。history.pushState()的第三个参数是一个url,并且必须是当前页面的url:请改用location.href - JonBrave
4
这对我有用。只需将“no-back-button”更改为“window.top.location.pathname + window.top.location.search”,即可使页面保留当前的页面名称,即使刷新也是如此。 - Steve
除其他方法外,这个对我有用,请点赞。请参考https://dev59.com/j2Ij5IYBdhLWcg3wwHlr#25665232。 - user2171669
我已经探索了许多情况,这是单页网站的最佳解决方案。 - djdance
这是一个非常糟糕的解决方案,因为你正在改变URL,所以如果你多次点击后退和前进,Chrome将重定向到不存在的路径。 - Tallboy
在Chrome 75版本之后不再工作。请参见:https://support.google.com/chrome/thread/8721521?hl=en - gene b.

21

在Chrome 79中,所有被点赞的答案都对我没用。看起来自Chrome 75版本之后,Chrome改变了关于“返回”按钮的行为。请看此处:

https://support.google.com/chrome/thread/8721521?hl=en

然而,在那个Google帖子中,Azrulmukmin Azmi在最后提供的答案确实有效。这是他的解决方案。

<script>
    history.pushState(null, document.title, location.href);
    history.back();
    history.forward();
    window.onpopstate = function () {
        history.go(1);
    };
</script>

Chrome的问题在于,如果你不采取浏览器操作(如调用history.back),它就不会触发onpopstate事件。这就是为什么我已经将它们添加到脚本中。

我不完全理解他写的是什么,但显然在Chrome 75+中,阻止后退现在需要额外的history.back() / history.forward()


在经过长时间的搜索后,这个方法终于在Android浏览器上奏效了。其他我尝试过的脚本都无法检测到浏览器的返回按钮事件,但这个方法可以。非常感谢,再次感谢!已在Chrome 83的桌面版和移动版上测试并正常工作!Gene,你真是我的救星! - Ivan
即使用户没有在页面上点击任何地方也可以工作。谢谢! - Garvit Jain
非常感谢!这在任何浏览器和移动浏览器中都可以工作!像魔法一样有效。继续保持! :) - not_null
仍然可以正常工作,但是在我升级了浏览器到版本87.0.4280.66 (官方版本) (64位)之后,它就无法工作了。有什么解决方法吗? - Ninh Le
1
由于某些原因,如果页面已经加载并且没有导航发生(仍然停留在着陆页面上,在Android / Chrome 89上),它对我不起作用。我所做的是在着陆URL上重定向到不同的URL。如果用户在第一页上单击返回,则会发生重新加载,但至少我仍然在我的网站上。如果在任何导航之后点击返回,则确实不会采取任何操作,也不会有任何痕迹。 - Will59
这在我这里已经很长时间运行良好,但今天突然导致页面不断重新加载!(我使用的是 Firefox Dev 94.0) - Lisa DeBruine

17

React

在 React 项目中,对于模态组件,控制浏览器返回是必要的操作,需要实现模态框的打开和关闭。

  • stopBrowserBack: 停止浏览器返回按钮功能,并获取回调函数。这个回调函数是你想要的操作:

    const stopBrowserBack = callback => {
      window.history.pushState(null, "", window.location.href);
      window.onpopstate = () => {
        window.history.pushState(null, "", window.location.href);
        callback();
      };
    };
    
  • startBrowserBack: 恢复浏览器返回按钮功能:

    const startBrowserBack = () => {
      window.onpopstate = undefined;
      window.history.back();
    };
    

在你的项目中的使用:

handleOpenModal = () =>
  this.setState(
    { modalOpen: true },
    () => stopBrowserBack(this.handleCloseModal)
  );

handleCloseModal = () =>
  this.setState(
    { modalOpen: false },
    startBrowserBack
  );

14

这是我完成它的方式。

奇怪的是,在Google Chrome和Safari中更改window.location并不好用。

发现在Chrome和Safari中,location.hash不会创建历史记录条目。所以你需要使用pushstate。

这对我来说可以在所有浏览器中工作。

history.pushState({ page: 1 }, "title 1", "#nbb");
window.onhashchange = function (event) {
    window.location.hash = "nbb";
};

1
在IE9及以下版本中无法正常工作,不支持pushState。 - Alex
太好了。这是一个不错的方法,几乎在所有最新的浏览器中都可以使用。 - Venugopal M
1
在较新版本的IE中运行良好。只需直接放置在document.ready中:$(document).ready(function () { .... }); - Oppa Gingham Style
请记住,在“#nbb”之前必须添加您当前的URI。例如:“account#nbb”。 - Mladen Janjetovic

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