history-change: 检测 history 的变化(url)

一个可以检测URL变化的库,利用 hashchange/popstate 来实现
更新于: 2023-08-11 11:03:49
项目主页: https://github.com/afeiship/history-change

安装

yarn add @jswork/history-change

直接浏览器使用

<script src="https://unpkg.com/@jswork/history-change"></script>

用法

类 node 环境

import HistoryChange from '@jswork/history-change';

// app init
HistoryChange.init('hash');

// listen
window.addEventListener('historychange', (e) => {
  const { action, history } = e.detail;
  console.log('action/history :', action, history);
});

线上资源

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HistoryChange online version</title>
    <script src="https://unpkg.com/@jswork/history-change"></script>
  </head>
  <body>
    <nav>
      <a href="#1">111</a>
      <a href="#2">222</a>
      <a href="#3">333</a>
      <a href="#4">444</a>
    </nav>
    <script>
      HistoryChange.init('hash');

      window.addEventListener('historychange', (e) => {
        const { action, history } = e.detail;
        console.log('action/history :', action, history);
      });
    </script>
  </body>
</html>

预览

已知

  • hash 情况下: 实际上检测 replaceback 逻辑有问题
  • 用户直接操作浏览器的前进/后退,所引起的 pop/push/replace 都不准确
  • 本来想通过 location.replace 方法的改写,来实现 replace 方法的监听,发现这个思路行不通(Object.getOwnPropertyDescriptor 得知

知识点

  • Object.getOwnPropertyDescriptor: 用来获取原有属性是否可改写等信息

扩展

  • rewrite 方法
  • aop 可拦截的方法、属性

cheatsheet

知识点详情
replace 为什么不能改写
由此得知: Object.getOwnPropertyDescriptor(location,'replace')

{
    "writable": false,
    "enumerable": true,
    "configurable": false
}
replaceState 可以改写
Object.getOwnPropertyDescriptor(History.prototype,'replaceState')

{
    "writable": true,
    "enumerable": true,
    "configurable": true
}
replace 与 back 无法区分的场景
# 场景1
history: #1 -> #2 -> #3

# 此时使用 back(使用 replace API 也可以实现同样的操作)
1. history.length 即不会发生变化
2. current: #2