阻止在popstate发生时更改URL

时间:2018-01-03 15:28:05

标签: javascript browser-history popstate

您好我正在尝试实施"您确定要离开此页吗?"弹出远离具有未经提交的修改形式的页面的弹出窗口。该网站是使用自定义框架构建的单页面应用程序。

由于所有锚链接都由框架处理,因此可以看出单击侧面导航链接将导致页面更改并显示Bootstrap确认对话框。如果用户点击"确定"点击进行,并进行AJAX调用以拉出新的页面内容。如果他们点击"取消"模态被解雇,它们保留在当前页面上。

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

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

event.preventDefault,event.stopPropagation或在popstate中返回false不要阻止URL更改。 AFAIK你不能拦截" Back"按钮之前" popstate"。试着在window.history.replaceState里面" popstate"似乎也不起作用。

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

  1. 您可以在" popstate"中停止更改网址吗?事件?
  2. 你能否以某种方式改写历史记录" popstate"将URL更改回当前页面上的内容并保留上一个条目(如果您确定要在接受模式后通过它)?
  3. 我还没想到其他一些解决方案?
  4. 我原来的想法是阻止" popstate"然后让框架触发链接点击以加载新内容并在他们点击"是"但我还没有办法做到这一点。

    谢谢!

1 个答案:

答案 0 :(得分:0)

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

  1. 每次创建历史记录状态时,我都会生成一个时间戳作为guid
  2. 当前时间戳存储在顶级模块的变量中
  3. 当popstate出现时,将传入的历史状态guid与顶级模块guid进行比较
  4. 如果新的guid更大,我们会继续前进,如果不那么我们就会倒退
  5. 当用户单击后退/前进按钮时,哈希确实会更改为进入URL。如果用户单击取消,则运行history.go(direction),其中direction为1或-1,具体取决于时间戳。这会将URL设置回原来的状态,并且不会对历史堆栈执行任何奇怪的操作。顶级历史记录变量有一个标志,表示我们正在伪造页面更改,因此popstate中的链接加载逻辑不会被执行。
  6. 唯一的怪癖是,如果用户确实单击“是”以在发送和返回该请求时导航并创建历史记录对象,则不会更新顶级模块的guid。如果你这样做,guid比较会一直认为你后退,因为你刚刚添加的新事件将始终是最高的数字。如果您没有对历史记录网址提出新请求,这可能不是问题,但我们的框架不会像浏览器那样显示陈旧数据。

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