vue-router使用示例
vue-router路由原理
在解析源码前,先来了解下前端路由的实现原理。 前端路由实现起来其实很简单,本质就是监听 URL 的变化,然后匹配路由规则,
显示相应的页面,并且无须刷新。目前单页面使用的路由就只有两种实现方式:hash 模式和history 模式。
hash 模式:即使用 URL 的 hash 来模拟一个完整的 URL ,于是当 URL 改变时,页面不会重新加载。
history 模式:利用了 HTML5 新特性 history.pushState 来完成 URL 跳转。在浏览器不支持的情况下,vue-router会自动退到 hash 模式。
根据mode确定类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import { HashHistory } from './history/hash' import { HTML5History } from './history/html5' import { AbstractHistory } from './history/abstract'
// ... more
constructor(options: RouterOptions = {}) { // ... more
// 默认hash模式 let mode = options.mode || 'hash'
// 是否降级处理 this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
// 进行降级处理 if (this.fallback) { mode = 'hash' }
if (!inBrowser) { mode = 'abstract' } this.mode = mode
// 根据不同的mode进行不同的处理 switch (mode) { case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== 'production') { assert(false, `invalid mode: ${mode}`) } } }
|
可以看到,会判断是否支持 history , 然后根据 fallback 来确定是否要降级。然后,根据不同的 mode , 分别实例化不同的 history 。 (HTML5History、HashHistory、AbstractHistory)
├── history // 操作浏览器记录的一系列内容
│ ├── abstract.js // 非浏览器的history
│ ├── base.js // 基本的history
│ ├── hash.js // hash模式的history
│ └── html5.js // html5模式的history
不同模式的history的公共实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| export class History { router: Router; base: string; current: Route; pending: ?Route; cb: (r: Route) => void; ready: boolean; readyCbs: Array<Function>; readyErrorCbs: Array<Function>; errorCbs: Array<Function>;
+go: (n: number) => void; +push: (loc: RawLocation) => void; +replace: (loc: RawLocation) => void; +ensureURL: (push?: boolean) => void; +getCurrentLocation: () => string;
constructor (router: Router, base: ?string) { this.router = router this.base = normalizeBase(base) this.current = START this.pending = null this.ready = false this.readyCbs = [] this.readyErrorCbs = [] this.errorCbs = [] }
listen (cb: Function) { this.cb = cb }
onReady (cb: Function, errorCb: ?Function) { }
onError (errorCb: Function) { } transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) onComplete && onComplete(route) this.ensureURL()
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: 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) && route.matched.length === current.matched.length ) { this.ensureURL() return abort() } }) } updateRoute (route: Route) { const prev = this.current this.current = route this.cb && this.cb(route) this.router.afterHooks.forEach(hook => { hook && hook(route, prev) }) } }
|
hash模式的功能实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { pushHash(route.fullPath) onComplete && onComplete(route) }, onAbort) } replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { replaceHash(route.fullPath) onComplete && onComplete(route) }, onAbort) }
|
html5模式的功能实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { pushState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) }
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { replaceState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) }
|
abstract模式的功能实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { this.stack = this.stack.slice(0, this.index + 1).concat(route) this.index++ onComplete && onComplete(route) }, onAbort) }
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { this.stack = this.stack.slice(0, this.index).concat(route) onComplete && onComplete(route) }, onAbort) }
|
小结
相关