• 初阶:
      • hash:http://example.com/#abc/bbc
        • 使用 window.onhashchange监听变更事件,做出反应;直接修改页面hash,改变路由位置
        • 不会带到服务端,无法做SSR
        • 不利于做 seo;失去原生页面锚点定位能力
        • 兼容IE8
        • 不需要兼容处理
      • history: [http://example.com/abc/bbc](http://example.com/#abc/bbc)
        • 使用 HTML5 History Interface 的 popState 监听路由变化;使用 pushState()和replaceState()方法
        • history 对服务端来说与普通url一致,可以做 ssr,容易做seo优化
        • history 可以携带 state 对象,hash只能带字符串
        • 兼容 IE10
        • 需要服务端做兼容处理
    • 中阶:

      • history 依赖 popstate事件监听路由变化,但 pushState、replaceState 都不会触发这个事件,所以:

        • 监听所有 a 路由的click事件,拦截,调用 pushState 更改路由
        • 拦截 history 原生 pushState、replaceState 方法,为它们添加事件特性
          1. const listener = function (type) {
          2. var orig = history[type];
          3. return function () {
          4. var rv = orig.apply(this, arguments);
          5. var e = new Event(type);
          6. e.arguments = arguments;
          7. window.dispatchEvent(e);
          8. return rv;
          9. };
          10. };
          11. window.history.pushState = listener('pushState');
          12. window.history.replaceState = listener('replaceState');
      • hashchange 事件只有在hash变化的时候才会触发,所以初始化时还需要额外监听 load 事件

        1. // replaceState和pushState行为的监听
        2. initHistoryHook(cb: Function){
        3. let history:any = window.history
        4. let bindHistoryEventListener = function(type: string){
        5. let originEvent = history[type]
        6. console.log('arguments', arguments, this)
        7. return function(){
        8. let newEvent = originEvent.apply(this, arguments)
        9. // 事件发生时就会触发这个回调
        10. cb(type, arguments)
        11. return newEvent
        12. }
        13. }
        14. history.pushState = bindHistoryEventListener('pushState')
        15. history.replaceState = bindHistoryEventListener('replaceState')
        16. }