react-router/react-router-dom
最近看了react-router 源码,对react-router有了更深的理解,下面写点东西备忘:
react-router-dom 是对react-router 的扩展,而两者实现路由跳转的本质依赖于一个history 插件。
此history 插件 是对浏览器原生 history 的封装。
BrowserHistory
1.push
function push(path, state) {
...globalHistory.pushState({key: key,state: state}, null, href);
...
}
2.replace
function replace(path, state) {
...globalHistory.replaceState({key: key,state: state}, null, href);
...
}
3.Listeners
var PopStateEvent = 'popstate';
var HashChangeEvent = 'hashchange';
function checkDOMListeners(delta) {listenerCount += delta;if (listenerCount === 1 && delta === 1) {window.addEventListener(PopStateEvent, handlePopState);if (needsHashChangeListener) window.addEventListener(HashChangeEvent, handleHashChange);} else if (listenerCount === 0) {window.removeEventListener(PopStateEvent, handlePopState);if (needsHashChangeListener) window.removeEventListener(HashChangeEvent, handleHashChange);}}
总结 :history router 基于 html5 新增的 history API,pushState, replaceState,其用法如下:
history.pushState(state, title, url);
history.replaceState(state, title, url);
即:跳转到 url 路径(与当前页面处在同一个域 ,形如一个网站的
location.pathname 部分),指定新页面的标题 title,但是浏览器目前都忽略这个值,因此这里一般使用 null,state 为关联新地址的状态对象(刷新页面并不会丢失)。二者的区别就是,pushState 会增加一条浏览器记录,而replaceState 会替换当前历史记录。相同点是,均不会刷新当前页面,也不会发生真正的跳转,而是仅仅改变了地址栏的 URL(history、location 对象)。
同时 history router 通过 popstate 来监听变化。
hash router
1.push
function pushHashPath(path) {window.location.hash = path;
}
- replace
function replaceHashPath(path) {window.location.replace(stripHash(window.location.href) + '#' + path);
}
- Listeners
var HashChangeEvent$1 = 'hashchange';
function checkDOMListeners(delta) {listenerCount += delta;if (listenerCount === 1 && delta === 1) {window.addEventListener(HashChangeEvent$1, handleHashChange);} else if (listenerCount === 0) {window.removeEventListener(HashChangeEvent$1, handleHashChange);}}
总结: hash router 基于 location.hash = pathString 来更新网站路径。pathString 代表网址中 # 号后面直到 search 的部分。与 history 不同的是,如果两次赋值一样的时候,并不会触发 hashchange 和 popstate 方法。同时浏览器通过 hashchange 事件来监听路由变化。
MemoryHistory
在非浏览器环境,使用抽象路由实现导航的记录功能MemoryHistory,即在内存中保存的一个创建的虚拟路由对象。
getUserConfirmation
getUserConfirmation 约等于 vue-router 中路由守卫,它是在路由跳转时的钩子函数,当传入它时可以在getUserConfirmation 内控制时都进行路由跳转。
getUserConfirmation 的用法如下
<BrowserRoutergetUserConfirmation={(message, callback) => {// this is the default behaviorconst allowTransition = window.confirm(message);callback(allowTransition);}}
/>
即 当callback(true) 会跳转,callback(false) 不会跳转,那么我们看一下 在触发路由跳转时 做了什么操作
function confirmTransitionTo(location, action, getUserConfirmation, callback) {// TODO: If another transition starts while we're still confirming// the previous one, we may end up in a weird state. Figure out the// best way to handle this.if (prompt != null) {var result = typeof prompt === 'function' ? prompt(location, action) : prompt;if (typeof result === 'string') {if (typeof getUserConfirmation === 'function') {getUserConfirmation(result, callback); // 重点在这里} else {warning(false, 'A history needs a getUserConfirmation function in order to use a prompt message');callback(true);}} else {// Return false from a transition hook to cancel the transition.callback(result !== false);}} else {callback(true);}}
在进行跳转时会调用getUserConfirmation 传入result, callback
callback 什么函数呢? 以createBrowserHistory push 中的为例:
function push(path, state) {warning(!(typeof path === 'object' && path.state !== undefined && state !== undefined), 'You should avoid providing a 2nd state argument to push when the 1st ' + 'argument is a location-like object that already has state; it is ignored');var action = 'PUSH';var location = createLocation(path, state, createKey(), history.location);transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {if (!ok) return; // 传入非 true 则不进行任何操作var href = createHref(location);var key = location.key,state = location.state;if (canUseHistory) {globalHistory.pushState({key: key,state: state}, null, href);if (forceRefresh) {window.location.href = href;} else {var prevIndex = allKeys.indexOf(history.location.key);var nextKeys = allKeys.slice(0, prevIndex + 1);nextKeys.push(location.key);allKeys = nextKeys;setState({action: action,location: location});}} else {warning(state === undefined, 'Browser history cannot push state in browsers that do not support HTML5 history');window.location.href = href;}});}
可见 callback 中只有传入true 才可以执行下一步,由此我们可以通过 getUserConfirmation 实现路由拦截。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务

喜欢的朋友记得点赞、收藏、关注哦!!!