Skip to content

Commit

Permalink
2.Vue-router相关文章
Browse files Browse the repository at this point in the history
  • Loading branch information
yzsunlei committed Dec 2, 2019
1 parent 9fcbf6c commit bc7e76c
Show file tree
Hide file tree
Showing 4 changed files with 495 additions and 0 deletions.
16 changes: 16 additions & 0 deletions 2.2.Vue-router使用过程分析.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
layout: post
title: 2.2.Vue-router使用过程分析
category: 写教程
tag: vue-router
exception:
readtime: 12
---

## 注册

## 组件调用

## 对象调用

## 小结
235 changes: 235 additions & 0 deletions 2.3.Vue-router基本实现原理.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
---
layout: post
title: 2.3.Vue-router实现原理
category: 写教程
tag: vue-router
exception:
readtime: 8
---

## vue-router使用示例

## vue-router路由原理
在解析源码前,先来了解下前端路由的实现原理。 前端路由实现起来其实很简单,本质就是监听 URL 的变化,然后匹配路由规则,
显示相应的页面,并且无须刷新。目前单页面使用的路由就只有两种实现方式:hash 模式和history 模式。
hash 模式:即使用 URL 的 hash 来模拟一个完整的 URL ,于是当 URL 改变时,页面不会重新加载。
history 模式:利用了 HTML5 新特性 history.pushState 来完成 URL 跳转。在浏览器不支持的情况下,vue-router会自动退到 hash 模式。

## 根据mode确定类型
```vuejs
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的公共实现
```javascript
export class History {
router: 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 //route 设置当前route
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) //更新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: 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) //回调函数,这一步很重要,这个回调函数在index文件中注册,会更新被劫持的数据 _router
this.router.afterHooks.forEach(hook => {
hook && hook(route, prev)
})
}
}
```
## hash模式的功能实现
```javascript
//push方法
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.transitionTo(location, route => {
pushHash(route.fullPath)
onComplete && onComplete(route)
}, onAbort)
}
//replace方法
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.transitionTo(location, route => {
replaceHash(route.fullPath)
onComplete && onComplete(route)
}, onAbort)
}
```
## html5模式的功能实现
```javascript
//push
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模式的功能实现
```javascript
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)
}
```
## 小结
Loading

0 comments on commit bc7e76c

Please sign in to comment.