import Vue from 'vue'
import VueRouter from '../vuerouter'
//从我们自己的router中导入VueRouter
import Index from '../components/Index.vue'
Vue.use(VueRouter)
const routes = [
{
path:'/',
name:'Index',
component : Index
},
{
path:'/about',
name:'about',
component: ()=> import('@/views/about.vue')
},
{
path:'/home',
name:'home',
component: ()=> import('@/views/home.vue')
},
]
const router = new VueRouter({
mode:'history',
base: process.env.BASE_URL,
routes
})
export default router
import Vue from 'vue'
import App from './App.vue'
import router from './route'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
首先要明确手写Vue-router要做什么,下图是Vue-router的一个类图,详细的记录了VueRouter需要什么属性与方法
options:记录构造函数中传入的对象(这个对象里面有路由规则)
routeMap:是一个对象,用来记录路由地址和组件的对应关系,将来会把路由规则解析到routeMap里
data:是一个对象,里面有一个属性current,用来记录当前路由地址,这里使用data 是为了实现一个响应式的对象。
通过类图中的_可以发现install是一个静态的方法
let _Vue = null
export default class VueRouter {
static install (Vue) {
//判断当前插件是否被安装
if(VueRouter.install.installed){
return;
}
VueRouter.install.installed = true
// 把vue构造函数记录到全局变量
_Vue = Vue
// 把创建vue实例的时候传入的router对象注入到Vue实例上
//混入 mixed
_Vue.mixin({
beforeCreate() {
if(this.$options.router)
_Vue.prototype.$router = this.$options.router
},
})
}
}
constructor(options){
this.options = options
this.routerMap = {
} // 用于存储解析的router对象
this.data = _Vue.observable({
current:'/'
})
// this.init()
}
这样就实现了类图中的相关属性
这个方法的作用是把构造函数中传入的路由规则转变为键值对的形式,存储到上文提到的routeMap中
//遍历所有的路由规则,解析路由规则变为键值对的形式,存储到routermap里
createRouterMap(){
this.options.routes.forEach(route =>{
this.routerMap[route.path] = route.component
})
}
initComponents (Vue) {
Vue.component('router-link',{
props:{
to:String
//接收外部传入的to
},
// template:' '
render (h) {
return h('a',{
attrs:{
href:this.to
},
on:{
click:this.clickHandler
}
},[this.$slots.default])
},
methods: {
clickHandler(e){
history.pushState({
},'',this.to)
this.$router.data.current = this.to
e.preventDefault();
}
},
})
const _this = this
Vue.component('router-view', {
render(h) {
const component = _this.routerMap[_this.data.current]
return h(component)
},
})
}
initEvent(){
window.addEventListener('popstate',()=>{
this.data.current = window.location.pathname
})
}
这个方法是为了在浏览器中后退和前进的时候来加载并且渲染组件
let _Vue = null
export default class VueRouter {
static install (Vue) {
//判断当前插件是否被安装
if(VueRouter.install.installed){
return;
}
VueRouter.install.installed = true
// 把vue构造函数记录到全局变量
_Vue = Vue
// 把创建vue实例的时候传入的router对象注入到Vue实例上
//混入 mixed
_Vue.mixin({
beforeCreate() {
if(this.$options.router)
_Vue.prototype.$router = this.$options.router
// this.$options.router.init()
},
})
}
constructor(options){
this.options = options
this.routerMap = {
} // 用于存储解析的router对象
this.data = _Vue.observable({
current:'/'
})
this.init()
}
init(){
this.createRouterMap()
this.initComponents(_Vue)
this.initEvent()
}
//遍历所有的路由规则,解析路由规则变为键值对的形式,存储到routermap里
createRouterMap(){
this.options.routes.forEach(route =>{
this.routerMap[route.path] = route.component
})
}
initComponents (Vue) {
Vue.component('router-link',{
props:{
to:String
},
// template:' '
render (h) {
return h('a',{
attrs:{
href:this.to
},
on:{
click:this.clickHandler
}
},[this.$slots.default])
},
methods: {
clickHandler(e){
history.pushState({
},'',this.to)
this.$router.data.current = this.to
e.preventDefault();
}
},
})
const _this = this
Vue.component('router-view', {
render(h) {
const component = _this.routerMap[_this.data.current]
return h(component)
},
})
}
initEvent(){
window.addEventListener('popstate',()=>{
this.data.current = window.location.pathname
})
}
}
参考资料:
拉勾教育