vue-router源码之history类的浅析
程序员文章站
2023-12-16 12:30:10
当前版本: 3.0.3
类目录: src/history/base.js
前言:
对于vue-router来说,有三种路由模式history,hash,abs...
当前版本: 3.0.3
类目录: src/history/base.js
前言:
对于vue-router来说,有三种路由模式history,hash,abstract, abstract是运行在没有window的环境下的,这三种模式都是继承于history类,history实现了一些共用的方法,对于一开始看vue-router源码来说,可以从这里开始看起。
初始属性
router: router; 表示vuerouter实例。实例化history类时的第一个参数 base: string; 表示基路径。会用normalizebase进行规范化。实例化history类时的第二个参数。 current: route; 表示当前路由(route)。 pending: ?route; 描述阻塞状态。 cb: (r: route) => void; 监听时的回调函数。 ready: boolean; 描述就绪状态。 readycbs: array<function>; 就绪状态的回调数组。 readyerrorcbs: array<function>; 就绪时产生错误的回调数组。 errorcbs: array<function>; 错误的回调数组 // implemented by sub-classes <!-- 下面几个是需要子类实现的方法,这里就先不说了,之后写其他类实现的时候分析 --> +go: (n: number) => void; +push: (loc: rawlocation) => void; +replace: (loc: rawlocation) => void; +ensureurl: (push?: boolean) => void; +getcurrentlocation: () => string;
对于history类来说,主要是下下面两个函数的逻辑
transitionto
这个方法主要是对路由跳转的封装, location接收的是html5history,hashhistory,abstracthistory, oncomplete是成功的回调,onabort是失败的回调
transitionto (location: rawlocation, oncomplete?: function, onabort?: function) { const route = this.router.match(location, this.current) // 解析成每一个location需要的route this.confirmtransition(route, () => { this.updateroute(route) oncomplete && oncomplete(route) this.ensureurl() // fire ready cbs once if (!this.ready) { this.ready = true this.readycbs.foreach(cb => { cb(route) }) } }, err => { if (onabort) { onabort(err) } if (err && !this.ready) { this.ready = true this.readyerrorcbs.foreach(cb => { cb(err) }) } }) }
confirmtransition
这是方法是确认跳转,route是匹配的路由对象, oncomplete是匹配成功的回调, 是匹配失败的回调
confirmtransition(route: route, oncomplete: function, onabort?: function) { const current = this.current const abort = err => { // 异常处理函数 if (iserror(err)) { if (this.errorcbs.length) { this.errorcbs.foreach(cb => { cb(err) }) } else { warn(false, 'uncaught error during route navigation:') console.error(err) } } onabort && onabort(err) } if ( issameroute(route, current) && // in the case the route map has been dynamically appended to route.matched.length === current.matched.length ) { this.ensureurl() return abort() } <!-- 根据当前路由对象和匹配的路由:返回更新的路由、激活的路由、停用的路由 --> const { updated, deactivated, activated } = resolvequeue(this.current.matched, route.matched) <!-- 需要执行的任务队列 --> const queue: array<?navigationguard> = [].concat( // beforerouteleave 钩子函数 extractleaveguards(deactivated), // 全局的beforehooks勾子 this.router.beforehooks, // beforerouteupdate 钩子函数调用 extractupdatehooks(updated), // config里的勾子 activated.map(m => m.beforeenter), // async components resolveasynccomponents(activated) ) this.pending = route <!-- 对于queue数组所执行的迭代器方法 --> const iterator = (hook: navigationguard, next) => { if (this.pending !== route) { return abort() } try { hook(route, current, (to: any) => { if (to === false || iserror(to)) { // next(false) -> abort navigation, ensure current url this.ensureurl(true) abort(to) } else if ( typeof to === 'string' || (typeof to === 'object' && ( typeof to.path === 'string' || typeof to.name === 'string' )) ) { // next('/') or next({ path: '/' }) -> redirect abort() if (typeof to === 'object' && to.replace) { this.replace(to) } else { this.push(to) } } else { // confirm transition and pass on the value next(to) } }) } catch (e) { abort(e) } } runqueue(queue, iterator, () => { const postentercbs = [] const isvalid = () => this.current === route <!-- beforerouteenter 钩子函数调用 --> const enterguards = extractenterguards(activated, postentercbs, isvalid) const queue = enterguards.concat(this.router.resolvehooks) <!-- 迭代运行queue --> runqueue(queue, iterator, () => { if (this.pending !== route) { return abort() } this.pending = null oncomplete(route) if (this.router.app) { this.router.app.$nexttick(() => { postentercbs.foreach(cb => { cb() }) }) } }) }) }
结语:
每一次总结,都是对之前读源码的再一次深入的了解
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。