简易版实现
代码实现
JS
// vue-router.js
class HistoryRoute{
constructor(){
this.current = null
}
}
class VueRouter{
constructor(options){
this.options = options
this.mode = options.mode || 'hash'
this.routes = options.routes || []
this.routesMap = this.createMap(this.routes)
this.history = new HistoryRoute()
this.init() // 初始化路由方法
}
//刷新页面就会调用
init(){
//使用的是hash路由
if(this.mode === 'hash'){
location.hash ? "" : location.hash = '/'
// 首次进入页面时,让其路由改变以触发页面渲染
window.addEventListener('load', () => {
this.history.current = location.hash.slice(1)
})
window.addEventListener('hashchange', () => {
this.history.current = location.hash.slice(1)
})
//使用的是history
} else {
location.pathname ? '' : location.pathname = '/'
// 首次进入页面时,让其路由改变以触发页面渲染
window.addEventListener('load', () => {
this.history.current = location.pathname
})
window.addEventListener('popstate', () => {
this.history.current = location.pathname
})
}
}
push(){}
go(){}
back(){}
//可以把数组结构转化成对象结构
createMap(routes){
return routes.reduce((memo, current) => {
// memo 刚开始是一个空对象
memo[current.path] = current.component
return memo;
}, {})
}
}
// install 方法中第一个参数就是 Vue 构造器
VueRouter.install = function(Vue){
// 当使用Vue.use(Vue-router)时,调用install方法
Vue.mixin({
//给每个组件混入一个 beforeCreate 生命周期钩子
beforeCreate(){
// console.log(this.$options.name);
// 获取根组件
if(this.$options && this.$options.router){
// 找到根组件
// 把当前的实例挂载到 _root 上面
this._root = this // main 根组件
// 把 router 实例挂载到 _router 上
this._router = this.$options.router
// 监控路径变化,路径变化就刷新视图
// 和 vue 劫持 data 一样,给 history 设置 get 和 set,使 history 变成响应式
Vue.util.defineReactive(this, 'xxx', this._router, history)
}else{ // main ----> app ---> Home/About 所有组件中都是有router
this._root = this.$parent._root;
this._router = this.$parent._router;
}
// this.$options.name 获取组件的名字
Object.defineProperty(this, "$router", {
get(){
return this._root._router;
}
})
Object.defineProperty(this, "$route", {
get(){
return{
current:this._root._router.history.current
}
}
})
}
})
// Vue.component() 全局组件
Vue.component('router-link', {
props: {
to: String
},
render(h) {
let mode = this._self._root._router.mode;
return <a href={mode==='hash'?`#${this.to}`:this.to}>{this.$slots.default}</a>
}
})
Vue.component('router-view', {
render(h) {
let current = this._self._root._router.history.current;
let routesMap = this._self._root._router.routesMap;
return h(routesMap[current])
}
})
}
export default VueRouter
// vue-router.js
class HistoryRoute{
constructor(){
this.current = null
}
}
class VueRouter{
constructor(options){
this.options = options
this.mode = options.mode || 'hash'
this.routes = options.routes || []
this.routesMap = this.createMap(this.routes)
this.history = new HistoryRoute()
this.init() // 初始化路由方法
}
//刷新页面就会调用
init(){
//使用的是hash路由
if(this.mode === 'hash'){
location.hash ? "" : location.hash = '/'
// 首次进入页面时,让其路由改变以触发页面渲染
window.addEventListener('load', () => {
this.history.current = location.hash.slice(1)
})
window.addEventListener('hashchange', () => {
this.history.current = location.hash.slice(1)
})
//使用的是history
} else {
location.pathname ? '' : location.pathname = '/'
// 首次进入页面时,让其路由改变以触发页面渲染
window.addEventListener('load', () => {
this.history.current = location.pathname
})
window.addEventListener('popstate', () => {
this.history.current = location.pathname
})
}
}
push(){}
go(){}
back(){}
//可以把数组结构转化成对象结构
createMap(routes){
return routes.reduce((memo, current) => {
// memo 刚开始是一个空对象
memo[current.path] = current.component
return memo;
}, {})
}
}
// install 方法中第一个参数就是 Vue 构造器
VueRouter.install = function(Vue){
// 当使用Vue.use(Vue-router)时,调用install方法
Vue.mixin({
//给每个组件混入一个 beforeCreate 生命周期钩子
beforeCreate(){
// console.log(this.$options.name);
// 获取根组件
if(this.$options && this.$options.router){
// 找到根组件
// 把当前的实例挂载到 _root 上面
this._root = this // main 根组件
// 把 router 实例挂载到 _router 上
this._router = this.$options.router
// 监控路径变化,路径变化就刷新视图
// 和 vue 劫持 data 一样,给 history 设置 get 和 set,使 history 变成响应式
Vue.util.defineReactive(this, 'xxx', this._router, history)
}else{ // main ----> app ---> Home/About 所有组件中都是有router
this._root = this.$parent._root;
this._router = this.$parent._router;
}
// this.$options.name 获取组件的名字
Object.defineProperty(this, "$router", {
get(){
return this._root._router;
}
})
Object.defineProperty(this, "$route", {
get(){
return{
current:this._root._router.history.current
}
}
})
}
})
// Vue.component() 全局组件
Vue.component('router-link', {
props: {
to: String
},
render(h) {
let mode = this._self._root._router.mode;
return <a href={mode==='hash'?`#${this.to}`:this.to}>{this.$slots.default}</a>
}
})
Vue.component('router-view', {
render(h) {
let current = this._self._root._router.history.current;
let routesMap = this._self._root._router.routesMap;
return h(routesMap[current])
}
})
}
export default VueRouter
路由表
js
// routes.js
import Home from '../views/Home.vue'
import About from '../views/About.vue'
export default [
{path:'/home', component: Home},
{path:'/about', component: About},
]
// routes.js
import Home from '../views/Home.vue'
import About from '../views/About.vue'
export default [
{path:'/home', component: Home},
{path:'/about', component: About},
]
路由注册
JS
// index.js
import Vue from 'vue'
import VueRouter from './vue-router'
import routes from './routes'
//使用Vue.use就会调用install方法
Vue.use(VueRouter)
export default new VueRouter({
mode:'history',
routes
})
// index.js
import Vue from 'vue'
import VueRouter from './vue-router'
import routes from './routes'
//使用Vue.use就会调用install方法
Vue.use(VueRouter)
export default new VueRouter({
mode:'history',
routes
})