代码之家  ›  专栏  ›  技术社区  ›  Jonathan

防止在popstate发生时更改URL

  •  2
  • Jonathan  · 技术社区  · 7 年前

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

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

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

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

    事件preventDefault,事件。stopPropagation或在popstate内返回false不会阻止URL更改。好吧,你不能在“popstate”之前拦截“Back”按钮。正在尝试打开窗口。历史“popstate”中的replaceState似乎也不起作用。

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

    1. 您能否阻止URL在“popstate”事件中更改?
    2. 如果您确定要在模式被接受后通过,是否可以在“popstate”中以某种方式重写历史记录,将URL更改回当前页面上的URL,并保留以前的条目?
    3. 还有什么我没想到的解决方案?

    我最初的想法是阻止“popstate”中的URL更改,然后让框架触发链接单击以加载新内容,如果他们单击“Yes”,则更改URL,但我还没有找到这样做的方法。

    谢谢

    1 回复  |  直到 7 年前
        1
  •  0
  •   Jonathan    7 年前

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

    1. 每次创建历史状态时,我都会生成一个时间戳作为guid
    2. 当前时间戳存储在顶层模块的变量中
    3. 发生popstate时,将传入历史记录状态的guid与顶级模块guid进行比较
    4. 如果新的guid更大,我们将前进,如果它更少,我们将后退
    5. 当用户单击后退/前进按钮时,哈希确实会更改为输入URL。如果用户单击“取消”,它将运行历史记录。go(方向),其中方向为1或-1,具体取决于时间戳。这会将URL设置回它应该的状态,并且不会对历史堆栈做任何奇怪的事情。顶层历史变量有一个标志,表明我们正在伪造页面更改,因此不会执行popstate中的链接加载逻辑。

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

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