最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

ReactRouter中的核心history库的详细分析

来源:懂视网 责编:小采 时间:2020-11-27 15:04:36
文档

ReactRouter中的核心history库的详细分析

ReactRouter中的核心history库的详细分析:这篇文章给大家介绍的内容是关于React Router中的核心history库的详细分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。前言使用React开发稍微复杂一点的应用,React Router几乎是路由管理的唯一选择。虽然React Router经历
推荐度:
导读ReactRouter中的核心history库的详细分析:这篇文章给大家介绍的内容是关于React Router中的核心history库的详细分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。前言使用React开发稍微复杂一点的应用,React Router几乎是路由管理的唯一选择。虽然React Router经历

这篇文章给大家介绍的内容是关于React Router中的核心history库的详细分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

前言

使用React开发稍微复杂一点的应用,React Router几乎是路由管理的唯一选择。虽然React Router经历了4个大版本的更新,功能也越来越丰富,但无论怎么变,它的核心依赖history库却一直没变。下面我们来了解下这个在github上有4k+星的库到底提供了什么功能。

HTML5 history对象

聊到history库,是不是觉得这个单词有点熟悉?不错,HTML5规范里面,也新增了一个同名的history对象。下面我们来看下这个history对象用来解决什么问题。

在jQuery统治前端的年代,通过ajax请求无刷新更新页面是当时相当流行的页面处理方式,SPA的雏形就是那时候演化出来的。为了标示页面发生的变化,方便刷新后依然能显示正确的页面元素,一般会通过改变url的hash值来唯一定位页面。但这会带来另一个问题:用户无法使用前进/后退来切换页面。

为了解决这个问题,history对象应运而生。当页面的url或者hash发生变化的时候,浏览器会自动将新的url push到history对象中。history对象内部会维护一个state数组,记录url的变化。在浏览器进行前进/后退操作的时候,实际上就是调用history对象的对应方法(forward/back),取出对应的state,从而进行页面的切换。

除了操作url,history对象还提供2个不用通过操作url也能更新内部state的方法,分别是pushStatereplaceState。还能将额外的数据存到state中,然后在onpopstate事件中再通过event.state取出来。如果希望对history对象作更深入的理解,可以参考 这里,和这里。

history库与HTML5 history对象的关系

我们再回过头来看history库。它本质上做了以下4件事情:

  1. 借鉴HTML5 history对象的理念,在其基础上又扩展了一些功能

  2. 提供3种类型的history:browserHistory,hashHistory,memoryHistory,并保持统一的api

  3. 支持发布/订阅功能,当history发生改变的时候,可以自动触发订阅的函数

  4. 提供跳转拦截、跳转确认和basename等实用功能

再对比一些两者api的异同。以下是history库的:

const history = {
 length, // 属性,history中记录的state的数量
 action, // 属性,当前导航的action类型
 location, // 属性,location对象,封装了pathname、search和hash等属性
 push, // 方法,导航到新的路由,并记录在history中
 replace, // 方法,替换掉当前记录在history中的路由信息
 go, // 方法,前进或后退n个记录
 goBack, // 方法,后退
 goForward, // 方法,前进
 canGo, // 方法,是否能前进或后退n个记录
 block, // 方法,跳转前让用户确定是否要跳转
 listen // 方法,订阅history变更事件
 };

以下是HTML5 history对象的:

const history = {
 length, // 属性,history中记录的state的数量
 state, // 属性,pushState和replaceState时传入的对象
 back, // 方法,后退
 forward, // 方法,前进
 go, // 方法,前进或后退n个记录
 pushState, // 方法,导航到新的路由,并记录在history中
 replaceState // 方法,替换掉当前记录在history中的路由信息
}

// 订阅history变更事件
window.onpopstate = function (event) {
 ...
}

从对比中可以看出,两者的关系是非常密切的,history库可以说是history对象的超集,是功能更强大的history对象。

createHashHistory源码分析

下面,我们以三种history类型中的一种,hashHistory为例,来分析下history的源码,看看它都干了些什么。先看下它是怎么处理hash变更的。

// 构造hashHistory对象
const createHashHistory = (props = {}) => {
 ...
 const globalHistory = window.history; // 引用HTML5 history对象
 ...
 // transitionManager负责控制是否进行跳转,以及跳转后要通知到的订阅者,后面会详细讨论
 const transitionManager = createTransitionManager();
 ...
 // 注册history变更回调的订阅者
 const listen = listener => {
 const unlisten = transitionManager.appendListener(listener);
 checkDOMListeners(1);

 return () => {
 checkDOMListeners(-1);
 unlisten();
 };
 };
 
 // 监听hashchange事件
 const checkDOMListeners = delta => {
 listenerCount += delta;

 if (listenerCount === 1) {
 window.addEventListener(HashChangeEvent, handleHashChange);
 } else if (listenerCount === 0) {
 window.removeEventListener(HashChangeEvent, handleHashChange);
 }
 };
 
 // hashchange事件回调
 const handleHashChange = () => {
 ...
 // 构造内部使用的location对象,包含pathname、search和hash等属性
 const location = getDOMLocation(); 
 ...
 handlePop(location);
 };
 
 // 处理hash变更逻辑
 const handlePop = location => {
 ...
 const action = "POP";
 // 给用户展示确认跳转的信息(如果有的话),确认后通知订阅者。如果用户取消跳转,则回退到之前状态
 transitionManager.confirmTransitionTo(location, action, getUserConfirmation, ok => {
 if (ok) {
 setState({action, location}); // 确认后通知订阅者
 } else {
 revertPop(location); // 取消则回退到之前状态
 }
 });
 };
 
 // 更新action,location和length属性,并通知订阅者
 const setState = nextState => {
 Object.assign(history, nextState);

 history.length = globalHistory.length;

 transitionManager.notifyListeners(history.location, history.action);
 };
 ...
}

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文档

ReactRouter中的核心history库的详细分析

ReactRouter中的核心history库的详细分析:这篇文章给大家介绍的内容是关于React Router中的核心history库的详细分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。前言使用React开发稍微复杂一点的应用,React Router几乎是路由管理的唯一选择。虽然React Router经历
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top