Vue-Router实现

241 阅读1分钟

Vue-Router

Vue-Router是一个插件,需要是用Vue.use()去使用。要求必须要有一个install方法,将来会被调用。

我们当前使用hash模式去实现,当前全部路由表如下:

import Vue from 'vue'
import VueRouter from './kvue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

//VueRouter是一个插件
// 内部做了什么
// 1:实现并声明了两个组件router-view  router-link
// 2:install:this.$router.push()
const routes = [{
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import( /* webpackChunkName: "about" */ '../views/About.vue'),
        children: [{
            path: '/about/info',
            name: 'info',
            component: {
                render(h) {
                    return h('div', 'info page')
                }
            }
        }, ]
    }
]

const router = new VueRouter({
    mode: 'hash',
    base: process.env.BASE_URL,
    routes
})

export default router

Vue-router插件代码

import View from './krouter-view'
//1.插件
//2.两个组件

//vue插件:
// function  object
// 要求必须有一个install方法,将来会被Vue.use调用

let Vue //保存Vue的构造函数,插件中使用
class VueRouter {
    constructor(options){
        this.$options=options
        // 设置初始化页面路由路径
        this.current=window.location.hash.slice(1)||'/'
        // 设置一个响应式数组,用来记录当前路由所有层级
        Vue.util.defineReactive(this,'matched',[])
        // 初始化路由表
        this.match()
        window.addEventListener('hashchange',this.onHashChange.bind(this))
        window.addEventListener('load',this.onHashChange.bind(this))
        // 创建一个路由映射表
        // this.routeMap={}
        // options.routes.forEach(route=>{
        //     this.routeMap[route.path]=route
        // })
    }
    match(routes){
        routes=routes||this.$options.routes
        // 下面规则是根据我自己的路由表写的
        for(const route of routes){
            if(route.path==='/'&&this.current==='/'){
                this.matched.push(route)
                return 
            }
            // 判断路由地址是否在当前路径内,想路由表内添加祖先路由,递归调用
            if(route.path!=='/'&&this.current.indexOf(route.path)!=-1){
                this.matched.push(route)
                if(route.children){
                    this.match(route.children)
                }
                return
            }
        }
    }
    onHashChange(){
        console.log(window.location.hash.slice(1))
        this.current=window.location.hash.slice(1)
        this.matched=[]
        this.match()
    }
}
VueRouter.install = function (_Vue) {
    Vue = _Vue
    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router
            }
        }
    })
    Vue.component('router-link', {
        props:{
            to:{
                type:String,
                require:true
            }
        },
        render(h) {
            return h('a',{attrs:{href:'#'+this.to}},this.$slots.default)
        }
    })
    Vue.component('router-view',View)
}

export default VueRouter

krouter-view代码

export default {
    render(h){
        // 标记当前router-view深度
        this.$vnode.data.routerView=true
        // 记录路由深度
        let depth=0
        let parent=this.$parent
        // 递归遍历父组件记录当前路由深度
        while(parent){
            const vnodeData=parent.$vnode&&parent.$vnode.data
            if(vnodeData){
                if(vnodeData.routerView){
                    depth++
                }
            }
            parent=parent.$parent
        }
        let component=null
        const route=this.$router.matched[depth]
        if(route){
            component=route.component
        }
        return h(component)
    }
}