如何区分浏览器返回和用户手动更改位置哈希

How distinguish between browser back and user manually changing location hash

问题

给定从 /page.html#A/page.html#B 的导航,有没有办法区分用户:

  1. 单击浏览器的 'back' 按钮,然后
  2. 手动将 url 改回 /page.html#A ?

背景/背景

我正在构建一个 Web 应用程序,其中单个页面在多张内容幻灯片之间转换,每张幻灯片都由特定的位置哈希值标识,例如 '#A''#B'.

例如,当用户在幻灯片 'A' 上并选择选项 'B' 时,位置从 /page.html#A 变为 /page.html#B

转换后,location.hash==#Bback()(通过 JS 或浏览器按钮)将 return 用户 location.hash==#A

但是,没有什么可以阻止用户手动更改 URL 栏中的散列。在这种情况下,浏览器会认为这是向前导航,在向后历史记录中插入 /page.html#B。也就是说,导航历史记录将是 #A > #B > #A 并且现在点击返回会将用户带到 #B.

我需要区分这两种情况,以便当我知道用户手动更新了 url 哈希时,我可以触发 go(N) 来同步浏览器 back/next 状态。

到目前为止的尝试次数

1) HTML5 popstate 事件:
我曾希望 html5 popstate 事件 ( https://developer.mozilla.org/en-US/docs/Web/Events/popstate ) 只会在案例 #1 中触发,但我可以确认它在两种情况下都会触发。

2) 浏览器 .onhashchange 事件
我可以确认如果存在,事件在两种情况下都会被触发

3) jQuery 手机 hashChange() 我可以确认在这两种情况下都被解雇了

4) 读取浏览器导航历史
我接下来的想法是维护一个哈希历史的JS数组,并比较新的哈希和浏览器历史是否与JS数组匹配,但是出于安全原因,JS无法读取浏览器位置历史。

想法

我知道如果我调用 window.history.forward() 并且没有页面存在,则什么也不会发生。我在想一个哈希历史的 JS 数组,调用 forward(),检查新的 location.hash(现在安全允许),与 JS 数组进行比较,然后调用 go(N) 来同步浏览器 back/next 状态。但是有点乱。

由于 javascript 中没有后退按钮事件,我建议最好的办法是在您的页面上创建您自己的后退按钮

看:How to Detect Browser Back Button event - Cross Browser

是的,你可以区分:

  1. 单击 back()/forward() 浏览器按钮,然后
  2. 在浏览器中手动编辑location.hash栏URL

也可以将两者与页内 HTML 元素导航一起使用。

问题:

  1. 浏览器 back()forward()go() 调用不会立即更新 location.hash。需要通过 setTimeout() 等待 ~10ms 让浏览器完成导航和更新 location.

解决方案(伪代码):

  • 维护一个backward_history_hashes的数组(注意'backwards'是逻辑上的,不是时间上的)
  • 保持值current_location.hash
  • 维护一个数组forward_history_hashes
  • 维护 in-page 导航的布尔标志,默认为 FALSE
  • 维护一个布尔标志是否ignore_hash_change
  • 创建一个 setTimeout() 监视器来检查 location.hash 变化

在每种情况下,历史数组都是 location.hashes

的简单字符串数组

on_in_page_navigation()

  • 设置in_page_flag = true
  • 通过 back()forward()go(N)
  • 触发浏览器导航
  • 设置in_page_flag = false

on_location_hash_change()

  • 设置ignore_hash_change=true
  • if(! in_page_flag)rewrite_browser_history()
  • 显示新内容对应location.hash
  • 设置ignore_hash_change = false

rewrite_browser_history()

  • 假设它是手动 URL 编辑,并使用 JS 历史数组触发 back()forward() 调用以生成所需的浏览器历史记录
  • 执行go(N)到所需的location.hash以同步浏览器历史与JS历史数组