Javascript 防止在popstate发生时更改URL

Javascript 防止在popstate发生时更改URL,javascript,browser-history,popstate,Javascript,Browser History,Popstate,您好,我正在尝试实现一个“您确定要离开此页面吗?”弹出窗口,当导航离开带有未提交的修改表单的页面时。该网站是一个使用自定义框架构建的单页应用程序 由于所有锚定链接都是由框架处理的,因此可以看出单击侧导航链接将导致页面更改并显示引导确认对话框。如果用户单击“Ok”,则单击将通过并发出AJAX调用来提取新页面内容。如果他们单击“取消”,模式将被取消,并停留在当前页面上 我一直无法解决的问题是,当用户在他们的web浏览器中单击“后退”按钮时。这将触发“popstate”事件。所有导航/历史都使用历史A

您好,我正在尝试实现一个“您确定要离开此页面吗?”弹出窗口,当导航离开带有未提交的修改表单的页面时。该网站是一个使用自定义框架构建的单页应用程序

由于所有锚定链接都是由框架处理的,因此可以看出单击侧导航链接将导致页面更改并显示引导确认对话框。如果用户单击“Ok”,则单击将通过并发出AJAX调用来提取新页面内容。如果他们单击“取消”,模式将被取消,并停留在当前页面上

我一直无法解决的问题是,当用户在他们的web浏览器中单击“后退”按钮时。这将触发“popstate”事件。所有导航/历史都使用历史API进行管理,因为它是一个单页应用程序

问题是,当有人单击“后退”时,URL会在“popstate”出现后发生更改,然后我会显示我的“你确定要离开吗?”模式。当事件发生时,地址栏中的URL现在显示您将从历史记录中转到的页面,而不是您当前查看的页面。如果您在引导程序中单击“取消”,请确认您现在的地址栏中显示了错误的URL

popstate内的event.preventDefault、event.stopPropagation或return false不会阻止URL更改。抱歉,你不能在“popstate”之前截取“Back”按钮。尝试在“popstate”中打开window.history.replaceState似乎也不起作用

有没有人有办法解决这个问题

  • 您能否阻止URL在“popstate”事件中更改
  • 如果您确定要在模式被接受后通过,是否可以在“popstate”中以某种方式重写历史记录,将URL更改回当前页面上的状态,并保留以前的条目
  • 还有其他我没想到的解决办法吗
  • 我最初的想法是在“popstate”中阻止URL更改,然后让框架触发链接单击以加载新内容,如果他们单击“Yes”,则更改URL,但我还没有找到这样做的方法


    谢谢

    我通过以下方法解决了这个问题:

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


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

    我所能想到的就是为每个pushState添加一个自定义状态变量,这样您就可以检测用户是向前还是向后,然后在用户选择取消时使用
    history.go()
    执行相反的操作。设置状态检测可能很棘手。