history是一个包, 可以在js运行的地方管理历史会话历史。 该包抹平了一些不同环境中的差异,提供一致的API用于操作和管理历史中访问记录、导航和会话之间的持久状态

Listener

listener 可以向一个history实例中注册一个监听,会在操作开始前去执行,内部统一由createEvents创建

  1. type Events<F> = {
  2. length: number;
  3. push: (fn: F) => () => void;
  4. call: (arg: any) => void;
  5. };
  6. function createEvents<F extends Function>(): Events<F> {
  7. let handlers: F[] = [];
  8. return {
  9. get length() {
  10. return handlers.length;
  11. },
  12. push(fn: F) {
  13. handlers.push(fn);
  14. return function() {
  15. handlers = handlers.filter(handler => handler !== fn);
  16. };
  17. },
  18. call(arg) {
  19. handlers.forEach(fn => fn && fn(arg));
  20. }
  21. };
  22. }

histoy instance

// history实例接口
interface History<S extends object = object> {
  readonly action: Action;
  readonly location: Location<S>;
  createHref(to: To): string;
  push(to: To, state?: S): void;
  replace(to: To, state?: S): void;
  go(delta: number): void;
  back(): void;
  forward(): void;
  listen(listener: Listener<S>): () => void;
  block(blocker: Blocker<S>): () => void;
}

注意的就是push方法, 用于向记录中添加一条记录。

push 开始执行时,首先或者下一个location对象, location对象是由原生的window.location 派生出来的也就是当前地址栏正在显示的。 后面会根据block 的信息决定是否进行跳转。

block监听的执行是原生的beforeunload 也就是在页面关闭、刷新时会执行. 如果是push方法用于跳转在这里会被执行页面history并不会被改变。 只有在调用retry 方法是才会继续。 对于原生的记录改变假如存在会优先执行block的逻辑,如果不存在会通知监听history事件的回调函数

hash mode

对于hash模式,监听了全局的hashchange 事件, 对于hashchange事件的触发时手动触发history的监听事件。如果popstate触发一致。 区别在于构建location对象时, state从history的记录中获取, 路由是hash后值。 所以在使用hash模式路由时,同样可以使用state。其余和history模式一致

memoryHistory

这种路由器是内部维护的一个数组也就是:

[
    0 = location,
  1 = location,
  3 = location
]

在push时会向数组中添加一个location对象,location对象由上次的location对象和本次提供的to path state参数行成