浏览器 - pushState、replaceState

636 阅读1分钟

1、监听浏览器 url 的变化

// 监听 hash 值的变化
window.onhashchange = function () {
    console.log('hashchange 触发!');
}


// 监听 url 的变化
// 1、触发事件:history.back、history.forward、history.go 三种事件
// 2、非触发事件:history.pushState、history.replaceState (通过手动拦截触发)
window.onpopstate = function () {
    console.log('popstate 触发!');
}


// 使用 addEventListener 监听 url 和 hash 的变化
// 1、使用 addEventListener 进行事件监听( 同时添加多个事件 )
// 2、最好不使用 window.onhashchange 多个会覆盖
// 3、监听 hash 值的变化( go、back、forward... )  
// 4、监听 popstate 的时候,此时路由已经完成的导航(只能做善后的工作)
window.addEventListener('hashchange' || 'popstate', function() {  
    // ...
    console.log('监听到url 或 hash 值的变化');
    // ...
}, false);

2、Histroy:历史记录前进与后退

window.history.back() // 后退一步
window.history.go(-1) // 后退一步
window.history.forward() // 前进一步
window.history.go(1) // 前进一步
window.history.go(n) // 前进n步   

3、Histroy:添加和修改历史记录中的条目

// 1、stateObject:javascript对象  
// 2、title:标题  
// 3、URL:新历史记录条目的 URL 由此参数指定
// 4、不会触发 popstate、hashchange 事件
history.pushState(stateObject,title,URL);
history.replaceState(stateObject,title,URL);

4、onpopstate 监听 history.pushState、history.replaceState 变化

<body>
  <div>
    <button id='pushState'>pushState </button>
    <button id='replaceState'>replaceState </button>
    <button id='forward'>forward </button>
    <button id='back'>back </button>
    <button id='go'>go </button>
  </div>
</body>

<script src="./index.js"></script>
<script>
  const btnPush = document.getElementById('pushState');
  const btnReplace = document.getElementById('replaceState');
  const btnForward = document.getElementById('forward');
  const btnBack = document.getElementById('back');
  const btnGo = document.getElementById('go');

  // 手动触发 pushState 事件
  btnPush.addEventListener('click', () => {
    history.pushState(null, null, '/aaa');
  }, true);

  // 手动触发 replaceState 事件
  btnReplace.addEventListener('click', () => {
    history.replaceState(null, null, '/bbb');
  }, true);

  // 手动触发 forward 事件
  btnForward.addEventListener('click', () => {
    history.forward()
  }, true);

  // 手动触发 back 事件
  btnBack.addEventListener('click', () => {
    history.back();
  }, true);

  // 手动触发 go 事件
  btnGo.addEventListener('click', () => {
    history.go(-1);
  }, true);

</script>

index.js

// 更改路由后去 挂载、更新子应用
function urlReroute(type) {
  return ()=>{
    console.log('触发事件',type);
  }
}

// 通过拦截监听 back、forward、go、popstate、replaceState 事件
window.addEventListener("popstate", urlReroute('pop'));


// 赋值自定义函数
window.history.pushState = patchedUpdateState(
  window.history.pushState,
  "pushState"
);
window.history.replaceState = patchedUpdateState(
  window.history.replaceState,
  "replaceState"
);


// 拦截 pushState 和 replaceState
function patchedUpdateState(updateState, methodName) {
  return function () {
    // 更新前的 url
    const urlBefore = window.location.href;
    // 执行 pushState 或者 replaceState 并返回结果
    const result = updateState.apply(this, arguments);
    // 更新后的 url
    const urlAfter = window.location.href;


    if(urlBefore != urlAfter){
      window.dispatchEvent(
        createPopStateEvent(window.history.state, methodName)
      );
    }
  };
}

// 使用 PopStateEvent 创建 popstate 事件对象
function createPopStateEvent(state, originalMethodName) {
  let evt;
  try {
    evt = new PopStateEvent("popstate", { state });
  } catch (err) {
    // IE 11
    evt = document.createEvent("PopStateEvent");
    evt.initPopStateEvent("popstate", false, false, state);
  }
  evt.singleSpa = true;
  evt.singleSpaTrigger = originalMethodName;
  return evt;
}