history是一个包, 可以在js运行的地方管理历史会话历史。 该包抹平了一些不同环境中的差异,提供一致的API用于操作和管理历史中访问记录、导航和会话之间的持久状态
Listener
listener 可以向一个history实例中注册一个监听,会在操作开始前去执行,内部统一由createEvents
创建
type Events<F> = {
length: number;
push: (fn: F) => () => void;
call: (arg: any) => void;
};
function createEvents<F extends Function>(): Events<F> {
let handlers: F[] = [];
return {
get length() {
return handlers.length;
},
push(fn: F) {
handlers.push(fn);
return function() {
handlers = handlers.filter(handler => handler !== fn);
};
},
call(arg) {
handlers.forEach(fn => fn && fn(arg));
}
};
}
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参数行成