按关键词阅读:
- popstate 事件是异步函数 。 由于通过 a 标签或 window.location 实现 URL 改变时 , 当前页面卸载 , 新的页面加载 。 由于 popstate 事件是异步的 , 在页面卸载之前并没来得及加载 。
- 只有触发新增的 pushState 与 replaceState 改变的历史记录条目 , 才会触发 popstate 事件 , 毕竟 popstate 事件的出现是为了配合 pushState 与 replaceState 。
2.调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件 , popstate 事件只会浏览器的某些行为下触发 。 由于各个浏览器的机制不同 , 测试结果也是不同的 。 我们先在 Chrome 浏览器下做个测试:
home.html
home html跳转至 cart.htmla 标签跳转至 classify.html
我们进行这样的操作:当前 URL 为 /home.html, 通过 history.pushState({ tag: "cart" }, "", "cart.html") 将当前 URL 变成了 /cart.html。 这个过程中 ,home.html 中的 popstate 事件确实没有触发 。 此时点击浏览器后退键 , URL 变回了 /home.html,home.html 中的 popstate 事件触发了 。那如果我们跳出 /home.html 的 document 呢?通过 history.pushState({ tag: "cart" }, "", "cart.html") 将当前 URL 变成了 /cart.html 后 , 点击 a 标签将 URL 变为 /classify.html。
文章插图
执行到这里 , 我们需要明确一点:a 标签改变 URL , 浏览器会重新发起请求 , 页面发生了跳转 , window 对象也发生了改变 。 popstate 官方文档第一句指出: popstate 事件是在对应 window 对象上触发 。 此时 , 我们点击浏览器后退键 , URL 变成 /cart.html, 执行 /cart.html 中的 load 事件 , 页面加载 。 再次点击浏览器后退键 , URL 变为 /home.html,/cart.html 中的 popstate 事件触发 , 页面未渲染 。
文章插图
popstate 事件虽然触发了 , 但是是 cart.html 页面中定义的 popstate 事件 , 并不是 home.html 的事件 。 并且同样的浏览器回退键操作 , 在 Safari 浏览器的展示是这样的:
文章插图
在浏览器回退时 , Safari 浏览器与 Chrome 浏览器对于页面的加载出现了差异 。classify.html 回退到 cart.html, URL 变成了 /cart.html ,但触发了 home.html 中的 popstate 事件 , 继续回退 , URL 变成了 /home.html , 依然触发了 home.html 中 popstate 事件 。
Chrome 浏览器与 Safari 浏览器差异的产生与浏览器对 popstate 事件处理有关系 。 至于浏览器内部是怎样处理的 , 小编也没有研究清楚 。 虽然 Chrome 浏览器与 Safari 浏览器对于 popstate 事件的处理方式不一样 , 但是 URL 的回退路径是一致的 , 完全符合历史记录后进先出的规则 。
在实际开发中 , 这种情况也是存在的:URL 由 /home.html 到 /cart.html 的改变 , 就类似单页面开发中的跳转 。 若此时在 cart.html 中 , 需要使用 pushState 跳出单页面 , 进入登录页 , 用户在登录页点击浏览器回退 , 或移动端手势返回 。 上述情况就会出现 , Chrome 浏览器与 Safari 浏览器渲染页面不一致 。
popstate 官网描述是“popstate 事件会在 对应 window 对象 上触发” , 注意是 对应 window 对象, 这个概念就比较模糊了 , 指的是触发 pushState 的 window 对象 , 还是 pushState 新定义的 window 对象 。 根据我们上述的测试 , 都有可能触发 popstate 事件 。 所以童鞋们 , 在遇到上面情况时 , 一定不要忘记在相关的两个页面中都要做 popstate 监听处理 。
3.a 标签的锚点也可以触发 popstate 事件的方法与 pushState 和 replaceState 不同 , a 标签锚点的变化会立即触发 popstate 事件 。 这里我们扩展一下思路 , a 标签做的事情就是改变了 hash 值 , 那通过 window.location 改变 hash 值是不是也是能立即触发 popstate 。 答案是肯定的 , 也会立即触发 popstate 。
通过 hash 小节的了解 , hash 值的改变会触发 hashchange 事件 , 所以 , hash 值的改变会同时触发 popstate 事件与 hashchange 事件 , 但如果改变的 hash 值与当前 hash 值一样的话 , hashchange 事件不触发 , popstate 事件触发 。 之前我们说过 ,window.location 设置的 hash 值必须与当前 hash 值不一样才能新建一条历史记录 , 而 pushState 却可以 。
结合上述 , 在浏览器支持 pushState 的情况下 , hash 模式路由也可以使用 pushState 、replaceState 和 popstate 实现 。 pushstate 改变 hash 值 , 进行跳转 , popstate 监听 hash 值的变化 。 小小的剧透 , vue-router 中不管是 hash 模式 , 还是 history 模式 , 只要浏览器支持 history 的新特性 , 使用的都是 history 的新特性进行跳转 。
稿源:(未知)
【傻大方】网址:http://www.shadafang.com/c/111J3025H020.html
标题:SPA 路由三部曲之核心原理( 四 )