1. 路由使用
首先我们来分析src/router/index.js
- Vue.use 注册路由插件,内部其实是用来调用VueRouter类中的静态方法install
- 创建VueRouter类的实例对象router,给VueRouter类中传入路由规则routes
接着来看src/main.js
- 创建Vue实例时给Vue类中传入VueRouter的实例对象router
2. 简版VueRouter实现
先来看看 VueRouter 类图,整体结构如下:
静态方法 install 和 构造函数 contructor
let _Vue = null
export default class VueRouter {
static install (Vue) {
// 1.判断是否已经安装VueRouter
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
// 2.将Vue保存在全局变量中,供后续注册router-link和router-view使用
_Vue = Vue
// 3.在声明Vue实例时将router注入到每个Vue实例中
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
}
}
})
}
constructor (options) {
// options为传入的路由规则routes
this.options = options
// 之后createRouteMap方法中将routes中的path作为key,component作为value
this.routeMap = {}
// observable用来将data设置为响应式对象,current为当前路由路径
this.data = _Vue.observable({
current: '/'
})
}
}
初始化 routeMap 的 createRouteMap 方法
createRouteMap () {
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
注册 router-link 和 router-view 组件 initComponent 方法
- h函数参考Vue官网: cn.vuejs.org/v2/guide/re…
- history.pushState参考MDN: developer.mozilla.org/zh-CN/docs/…
- window.popstate参考MDN: developer.mozilla.org/zh-CN/docs/…
initComponent (Vue) {
Vue.component('router-link', {
props: {
to: String
},
// h函数用来创建a标签并渲染,this.$slots.default为router-link的children
render (h) {
return h('a', {
attr: {
href: this.to
},
on: {
click: this.clickHandler
}
}, [this.$slots.default])
},
methods: {
// 用来组织a标签默认跳转及设置路由地址
clickHandler (e) {
history.pushState({}, "", this.to)
this.$router.data.current = this.to
e.preventDefault()
}
}
})
const self = this
Vue.component('router-view', {
render (h) {
// 找到当前路由对应的组件,h函数渲染对应组件
const component = this.routeMap[self.data.current]
return h(component)
}
})
}
浏览器记忆处理 initEvent 方法
initEvent () {
// 浏览器前进后退记忆处理
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname
})
}
3. 最后奉上完整代码
let _Vue = null
export default class VueRouter {
static install (Vue) {
// 1.判断是否已经安装VueRouter
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
// 2.将Vue保存在全局变量中,供后续注册router-link和router-view使用
_Vue = Vue
// 3.在创建Vue实例时将router注入到每个Vue实例中
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
this.init()
}
}
})
}
constructor (options) {
this.options = options
this.routeMap = {}
this.data = _Vue.observable({
current: '/'
})
}
init () {
this.createRouteMap()
this.initComponent(_Vue)
this.initEvent()
}
createRouteMap () {
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
initComponent (Vue) {
Vue.component('router-link', {
props: {
to: String
},
// h函数用来创建a标签并渲染,this.$slots.default为router-link的children
render (h) {
return h('a', {
attr: {
href: this.to
},
on: {
click: this.clickHandler
}
}, [this.$slots.default])
},
methods: {
// 用来组织a标签默认跳转及设置路由地址
clickHandler (e) {
history.pushState({}, "", this.to)
this.$router.data.current = this.to
e.preventDefault()
}
}
})
const self = this
Vue.component('router-view', {
render (h) {
// 找到当前路由对应的组件,h函数渲染对应组件
const component = this.routeMap[self.data.current]
return h(component)
}
})
}
initEvent () {
// 浏览器前进后退记忆处理
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname
})
}
}
支持原创,请勿抄袭