当popstate发生时阻止URL更改

问题描述 投票:2回答:1

嗨,我正在尝试实施“你确定要离开这个页面吗?”导航离开具有尚未提交的已修改表单的页面时弹出窗口。该网站是使用自定义框架构建的单页面应用程序。

由于所有锚链接都由框架处理,因此它可以告诉单击侧面导航链接将导致页面更改并显示Bootstrap确认对话框。如果用户单击“确定”,则单击将完成,并进行AJAX调用以提取新页面内容。如果他们单击“取消”,则模式将被解除,并且它们将保留在当前页面上。

我无法解决的部分是当用户点击其Web浏览器中的“后退”按钮时。这会触发“popstate”事件。所有导航/历史记录都使用历史记录API进行管理,因为它是单页面应用程序。

问题是,当有人点击“返回”时,网址会在“popstate”发生后发生变化,然后我会显示“你确定要离开吗?”模态。当事件发生时,地址栏中的URL现在会显示您将从历史记录中转到的页面,而不是您当前正在查看的页面。如果在Bootstrap中单击“取消”,则确认您的地址栏中显示的URL错误。

event.preventDefault,event.stopPropagation或在popstate中返回false不会阻止URL更改。 AFAIK你不能在“popstate”之前拦截“后退”按钮。在“popstate”中尝试window.history.replaceState似乎也不起作用。

有没有人有如何使这项工作的解决方案?

  1. 你可以阻止URL在“popstate”事件中更改吗?
  2. 您是否可以在“popstate”中以某种方式重写历史记录,以便将URL更改回当前页面上的内容并保留前一个条目(如果您确定要在接受模式后通过它)?
  3. 其他一些我没有想到的解决方案?

我原来的想法是阻止“popstate”中的URL更改然后让框架触发链接点击以加载新内容并更改URL如果他们点击“是”但我还没有找到方法来做到这一点。

谢谢!

javascript browser-history popstate
1个回答
0
投票

我通过以下方式解决了这个问题;

  1. 每次创建历史状态时,我都会生成一个时间戳作为guid
  2. 当前时间戳存储在顶级模块的变量中
  3. 当popstate出现时,将传入历史状态的guid与顶级模块guid进行比较
  4. 如果新的指导更大,我们就会前进,如果不是那么我们就会倒退
  5. 当用户单击后退/前进按钮时,散列会更改为进入URL。如果用户单击取消,则运行history.go(direction),其中direction为1或-1,具体取决于时间戳。这会将URL设置回原来的状态,并且不会对历史堆栈执行任何奇怪的操作。顶级历史记录变量有一个标志,表示我们正在伪造页面更改,因此不会执行popstate中的链接加载逻辑。

唯一的怪癖是,如果用户确实单击“是”以在发送和返回该请求时导航,并且创建了历史记录对象,则不会更新顶级模块的guid。如果你这样做,guid比较会一直认为你会后退,因为你刚刚添加的新事件将始终是最高的数字。如果您不对历史URL发出新请求,但这可能不是问题,但我们的框架确实如此,它不会像浏览器那样显示过时的数据。

这是不理想的,因为你确实看到URL更改(没有内容更改),但到目前为止似乎运行良好。我找到的另一个解决方案是将您自己站点的历史记录存储在本地/会话存储中,并比较URL而不是使用guid时间戳来查找popstate方向。这在Safari的隐私浏览模式下不起作用,因为两个存储层都被禁用,因此我选择了guid。

© www.soinside.com 2019 - 2024. All rights reserved.