打开模态弹出窗口时,防止移动设备的“返回按钮”退出站点,而应该关闭弹出窗口。

4

当模态弹出对话框被打开时,即使我添加一个关闭按钮(通常是在右上角的X),一些移动用户仍会使用他们的移动端“返回按钮”来关闭弹出窗口。但实际上这将退出网站!

如何使移动端“返回按钮”关闭弹出窗口而不是退出网站?

document.getElementById("link").onclick = function(e) {
  e.preventDefault();
  document.getElementById("popupdarkbg").style.display = "block";
  document.getElementById("popup").style.display = "block";
    document.getElementById('popupdarkbg').onclick = function() {
      document.getElementById("popup").style.display = "none";
      document.getElementById("popupdarkbg").style.display = "none";
  };
  return false;
}
#popup { display: none; position: fixed; top: 12%; left: 15%; width: 70%; height: 70%; background-color: white; z-index: 10; }
#popupdarkbg { position: fixed; z-index: 5; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden; background-color: rgba(0,0,0,.75); display: none; }
<div id="main">
<a href="" id="link">Click me</a><br>
</div>
<div id="popup">This is a popup window! Click mobile "Back button"</div>
<div id="popupdarkbg"></div>

备注:

  • 我已经看过这个 Codepen 如何使用 JavaScript 禁用浏览器后退按钮,但我不确定它在 Chrome、Firefox、Safari 以及 Android、iOS 等浏览器上是否跨浏览器。

  • 我已经看到关于 window.onpopstate = function () { history.go(1); }; 的答案,但我想确保这是在这里做的好方法(所以它不是重复的)。


pushState 在各种浏览器和平台上得到了很好的支持,这种方法是一种常见的做法。除非你特别针对 IE9 或更低版本进行开发,否则你不需要担心。 - Máté Safranka
@MátéSafranka,那么您会在弹出窗口打开时执行 window.onpopstate = function () { history.go(1); };,并在关闭弹出窗口时执行 window.onpopstate = function () { };(或其他操作)吗?这样,当弹出窗口关闭时,他们仍然可以返回到先前的网站。 - Basj
2个回答

3
以下是我在应用程序中如何处理的粗略版本:
var showModal = function() {
    // some code here to show the HTML elements...

    window.history.pushState('backPressed', null, null);
    window.history.pushState('dummy', null, null);
    window.addEventListener('popstate', hideModal, { once: true });
};

var hideModal = function(event) {
    if (event.state == 'backPressed') {
        // hide the HTML elements
    }
};

我添加两个虚拟状态的原因是,popstate 事件也会在 URL 哈希值更改时触发,例如用户在地址栏中手动覆盖哈希值。检查当前历史状态是否与 backPressed 匹配,让我可以验证该事件确实是由“返回”按钮触发的。

非常感谢。现在在Chrome for Android中使用它时可以工作,但是从应用程序中执行时却不行(我的应用程序只是一个显示网站的Android WebView:返回按钮会退出应用程序)。 - Basj
哎呀,很抱歉我无法确定地帮助你。根据我对 Android 开发的了解,你需要在 Android 应用程序中捕获后退事件,然后使用 WebView 对象的 API 以某种方式通知内部 JS 代码。从我查看的 Android WebView 参考文献来看,我猜测应该调用 goBack() 来模拟浏览器的返回按钮。 - Máté Safranka
1
非常感谢!注:Android WebView部分已经通过此答案直接解决。 - Basj
@MátéSafranka 我猜如果用户通过UI关闭模态框,你必须弹出状态? - Nuthinking

0
这是已接受答案 (*) 的一个小变化,我最终要使用的:
window.history.pushState('popupclosed', null, null);    // initial state: closed

var hideModal = function(event) {
    if (event.state == 'popupclosed') {
        closepopup();
    }
};

var showModal = function(event) {
    if (history.state !== 'opened') {
        window.history.pushState('opened', null, null);
    }
    window.addEventListener('popstate', hideModal, { once: true });   

与 (*) 的区别在于这里:

  • 我们每次在浏览器历史记录中打开弹出窗口时,只添加一个新状态,而不是两个

  • 如果以前的弹出窗口是使用弹出窗口右上角的 X 按钮关闭的(而不是使用“历史记录中的上一个”浏览器按钮或手机上的“返回按钮”),则在打开第二个弹出窗口时,不要重新创建新的历史状态opened,因为它已经是当前状态。


这个答案似乎很好用。 - chillywilly
为什么在下面的条件中使用history.state,而在语句中使用window.history? 这是有意为之还是因为historywindow.history之间的差异? - Esger
1
如果我没记错的话,它是一样的,但为了清晰起见,我应该在每个地方都放置 window.history - Basj

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