简易vue-router 源码实现

main.js中

import Vue from "vue";
import App from "./App.vue";
import router from './krouter'

Vue.config.productionTip = false;

Vue.prototype.$bus = new Vue();

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");

kvue-router.js   文件   --->  插件实现

let Vue;

class VueRouter {
    constructor(options) {
        this.$options = options

        // 创建一个路由的path和route映射
        this.routeMap = {}

        // 将来当前路径current需要响应式
        // 利用Vue的响应式原理可以做到这一点
        this.app = new Vue({
            data: {
                current: '/'
            }
        })
    }
    init(){
        // 绑定浏览器事件
        this.bindEvents()

        // 解析路由配置
        this.createRouteMap(this.$options)

        // 创建router-link 和 router-view
        this.initComponent()
    }
    bindEvents() {
        window.addEventListener('hashchange', this.onHashChange.bind(this))
        window.addEventListener('load', this.onHashChange.bind(this))
    }
    onHashChange() {
        // http://localhost/#/home   slice(1)可以把#去掉,拿后面的部分
        this.app.current = window.location.hash.slice(1) || '/'
    }
    createRouteMap(options){
        options.routes.forEach(item => {
            // ['/home']: {path: '/home', component: Home}
            this.routeMap[item.path] = item
        })
    }
    initComponent(){
        // 声明两个全局组件
        Vue.component('router-link', {
            props: {
                to: String
            },
            render(h) {
                // 目标是:<a :href="to">xxx</a>
                return h('a', {attrs: {href: '#'+this.to}}, this.$slots.default)

                // jsx写法
                // return <a href={this.to}>{this.$slots.default}</a>
            }
        })

        // hash -> current -> render
        Vue.component('router-view', {
            // 箭头函数能保留this指向,这里指向VueRouter实例
            render: (h) => {
                const Comp = this.routeMap[this.app.current].component
                return h(Comp)
            }
        })
    }
}

// 把VueRouter变为插件
VueRouter.install = function(_Vue) {
    Vue = _Vue // 这里保存,上面使用

    // 混入任务
    Vue.mixin({ // 混入就是扩展Vue
        beforeCreate() {
            // 这里的代码将来会再外面初始化的时候被调用
            // 这样外面就实现了Vue扩展
            // 这里的this就是Vue实例
            // 但是这里会在所有组件的创建过程中都执行,所以这里不健壮
            // Vue.prototype.$router = this.$options.router   

            // 这里只希望根组件执行一次
            if(this.$options.router){
                Vue.prototype.$router = this.$options.router
                // 路由进行初始化
                this.$options.router.init()
            }
        }
    })
}

export default VueRouter

krouter.js  --->  相当于router.js

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

// 插件注册
Vue.use(VueRouter)

export default new VueRouter({
    routes: [
        {path: "/", component: Home},
        {path: "/about", component: About}
    ]
})
原文地址:https://www.cnblogs.com/haishen/p/11309288.html