history 在 v5 之前使用单独的包, v6 之后再 router 包中单独实现。
路由切换的动作类型,包含三种类型:
Action 枚举:
export enum Action {
Pop = "POP",
Push = "PUSH",
Replace = "REPLACE",
}
关于三种动作类型意思,可以进入Actions了解。
创建一个含有唯一值key的location对象。
当前方法是一个公共方法,在createBrowserHistory/createHashHistory/createMemoryHistory中都使用其创建location对象。
如果你需要更深层次了解,请进入createLocation。
createBrowserHistory/createHashHistory函数都基于getUrlBasedHistory,执行getUrlBasedHistory后,会返回一个history对象。
history库文件暴露出createMemoryHistory、createBrowserHistory、createHashHistory三个方法,每种方法作用不一样。
createMemoryHistory:用于非 dom 环境,react-native 和测试环境
createBrowserHistory/createHashHistory:用于浏览器环境,createBrowserHistory对应于history路由模式,而createHashHistory应用于hash模式路由,两者方法的底层都是利用了HTML5 history API方法实现(即监听popstate事件及replaceState、pushState无刷新更改location URL)
createBrowserHistory/createHashHistory函数都基于getUrlBasedHistory ,提供不同的:
属性实现不同的 history 对象
action
当前location对象变化的动作类型,关于三种动作类型意思,可以进入Actions了解。
location
返回当前的location对象。
底层:getLocation => createLocation()
具体内容可访问createLocation。
listen(fn: Listener)
在createBrowserHistory函数(此刻以此举例)中,会有一个listener变量来接收传入的监听回调函数fn。
注意:一个history中,有且仅有一个活跃的listen监听函数,否则会抛出一个异常。
如果你想要继续传入一个监听回调事件,你可以先执行history.listen(fn)的返回值(作用:清除监听事件),再传入fn。
监听location变化的函数,传入一个回调函数fn,并将代表location变化的一个update对象传入回调函数中。
内部逻辑:
(1) 创建一个popstate监听事件,回调函数handlePop
(2) 将listener = fn;
(3)返回一个函数(作用:执行这个函数,可以取消当前的listener);
源码:
listen(fn: Listener) {
if (listener) {
throw new Error("A history only accepts one active listener");
}
window.addEventListener(PopStateEventType, handlePop);
listener = fn;
return () => {
window.removeEventListener(PopStateEventType, handlePop);
listener = null;
};
},
Listener interface
export interface Listener {
(update: Update): void;
}
Update interface
export interface Update {
action: Action; // 动作类型
location: Location; // 新的location对象
delta: number | null; // 目的location对象(也可以理解为新的location对象)与之前的location,在history栈中之间的增量
}
createHref(to)
创建地址
createBrowserHistory
如果to是一个string,返回to,否则createPath(to),如果想了解createPath,请访问createPath。
内部调用: createBrowserHref(window, to)
function createBrowserHref(window: Window, to: To) {
return typeof to === "string" ? to : createPath(to);
}
createHashHistory
如果to是一个string,返回to,否则createPath(to),如果想了解createPath,请访问createPath。
内部调用: createBrowserHref(window, to)
function createHashHref(window: Window, to: To) {
let base = window.document.querySelector("base");
let href = "";
if (base && base.getAttribute("href")) {
let url = window.location.href;
let hashIndex = url.indexOf("#");
href = hashIndex === -1 ? url : url.slice(0, hashIndex);
}
return href + "#" + (typeof to === "string" ? to : createPath(to));
}
go(n)
指定跳转地址,调用和HTML5 history api的go方法一样, 如果想了解原生的history,请访问history。
push
添加一个新的历史记录
function push(to: To, state?: any) {
// 1. 更改动作类型action
action = Action.Push;
// 2. 创建一个新的location对象
let location = createLocation(history.location, to, state);
if (validateLocation) validateLocation(location, to);
// 3. 当前索引idx
index = getIndex() + 1;
// 4. state状态对象{ idx: index,usr: state, key: 唯一的key值 }
let historyState = getHistoryState(location, index);
let url = history.createHref(location);
// try...catch because iOS limits us to 100 pushState calls :/
try {
globalHistory.pushState(historyState, "", url);
} catch (error) {
if (error instanceof DOMException && error.name === "DataCloneError") {
throw error;
}
window.location.assign(url);
}
if (v5Compat && listener) {
// 执行location变化的监听回调事件listener--调用history.listen中传入的事件
listener({ action, location: history.location, delta: 1 });
}
}
replace
替换当前的历史记录
function replace(to: To, state?: any) {
// 1. 更改动作类型action
action = Action.Replace;
// 2. 创建location对象
let location = createLocation(history.location, to, state);
if (validateLocation) validateLocation(location, to);
// 3. 返回state状态对象中的idx,否则返回null
index = getIndex();
// 生成一个新对象,包含usr、key、idx:
let historyState = getHistoryState(location, index);
// 创建新的URL path
let url = history.createHref(location);
// history API中的replaceState替换当前的历史记录
globalHistory.replaceState(historyState, "", url);
if (v5Compat && listener) {
listener({ action, location: history.location, delta: 0 });
}
}
更多内容,欢迎访问https://www.wangyuegyq.top