vue-router源码 浅尝辄止

296 阅读1分钟

Vue-Router 源码浅尝辄止

基本用法

  1. 安装: npm install vue-router --save-dev;

  2. 通常 创建router 文件夹用来管理路由

    ​ 上图是一个常用的 vue-cli的脚手架目录

    1. Index.js. 用来导出一个 vue-router 对象

      import Vue from 'vue'
      // import VueRouter from 'vue-router'; 注释调 之前vue-cli引入的 vue-router
      import VueRouter from './vueRouter.js'; // 改用我们自己的vue-router
      import Home from '../views/Home.vue'
      
      Vue.use(VueRouter)
      
      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')
        }
      ]
      
      const router = new VueRouter({
        routes
      })
      
      export default router
      
    2. Main.js 中注册router

      import Vue from 'vue'
      import App from './App.vue'
      import router from './router'
      
      Vue.config.productionTip = false
      
      new Vue({
        router,
        render: h => h(App)
      }).$mount('#app')
      
      
  3. 分析需求. usage :

    1. spa页面不能刷新,根据url显示对应的内容
    2. Vue-router 是一个插件 所以必须有静态方法 install
    3. 为了在每个vue 组件中使用。this.$router 需要给Vue.prototype.$router 挂在vue-router 实例
    4. 全局组件vue-router vue-review 不是白来的 需要全局注册
    5. 定义一个 响应式的数据 并监听 hashchange 事件 ,接受注册的路由表,跳转对应的组件

实现一个简单的hash mode router

该代码和 vue-router 是有些许的差别的,请自行研究具体细节



let Vue;
class VueRouter {
    constructor(options) {
        this.$options = options;
        this.matcher = createMatcher(options.routes || [],this);
        
    }
    init(app){
        // 为了简化 这里和源码有些出入
        const initial = window.location.hash.slice(1) || "/";

        Vue.util.defineReactive(app, '_route', this.matcher[initial])
        window.addEventListener("hashchange", () => {
            app._route = this.matcher[window.location.hash.slice(1)]
        })   
    }
}

VueRouter.install = function (_Vue) {
    Vue = _Vue;

    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                this._routerRoot = this;
                this._router = this.$options.router;
                this._router.init(this);
            }else{
                this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
            }
        }
    })

    Object.defineProperty(Vue.prototype, '$router', {
        get () { return this._routerRoot._router }
    })

    Object.defineProperty(Vue.prototype, '$route', {
        get () { return this._routerRoot._route }
    })
    Vue.component('router-link', {
        props: {
            to: {
                type: String,
                required: true
            }
        },
        render(h) {
            return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default)
        }
    });
    Vue.component('router-view', {
        render(h) {
            let component = null;
            if(this.$route.component){
                component = this.$route.component;
            }
            return h(component);
        }
    });

}

const createMatcher = function(routes){
    let obj = {};
    routes.forEach(route=>{
        obj[route.path] = route;
    })
    return obj;
}

export default VueRouter;

这样一个简单的 hashchange 的vue-router 就实现了