vue-router源码实现

1. 目录结构

在这里插入图片描述

2.实现vue-router源码

// kvue-router.js
/* eslint-disable */ // 禁止eslint
let Vue;
class VueRouter {
  constructor(options){ // router传入参数
    this.$options = options;
    this.routeMap = {}; // 所有的routes组件实例
    this.app = new Vue({ // 获取当前的vue
      data: {
        current: '/'
      }
    })
  }

  // vue-router初始化 任务
  init() {
    this.bindEvents();
    this.createRouteMap(this.$options);
    this.initComponent()
  }

  // 全局添加默认绑定任务
  bindEvents() {
    window.addEventListener('load',this.onHashChange.bind(this),false);
    window.addEventListener('hashchange',this.onHashChange.bind(this),false);
  }

  // 获取hash地址
  onHashChange() {
    this.app.current = window.location.hash.slice(1) || '/';
  }

  // 获取路由配置里面的地址
  createRouteMap(options) {
    options.routes.forEach(item => {
        this.routeMap[item.path] = item;
    })
}
  // 初始化默认router标签
  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)
          // 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.install = function(_vue){
  Vue = _vue;
  Vue.mixin({
    beforeCreate() {
      if(this.$options.router){
        // Vue.prototype.$router = this.$options.router; // 原型链上添加router属性
        this.$options.router.init() // 调用vue插件中的init方法
      }
    },
  })
}
export default VueRouter

3.路由配置页面引入kvue-router.js

// router.js
import Vue from 'vue' // 引入vue
import Router from './kvue-router' // 引入kvue-router

// 使用自定义router插件
Vue.use(Router)

// 实例化vue对象
const router = new Router({
  mode: 'hash',
  routes: [
    {
      path:'/home',
      title: 'home',
      component: () => import('./components/base/home.vue')
    },
    {
      path:'/list',
      title: 'list',
      component: () => import('./components/base/list.vue')
    },
  ]
})

export default router

4.main.js页面引入router文件,并且挂载到Vue上

// main.js 

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = true

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

5.app.vue文件显示router标签

// app.vue
<template>
  <div id="app">
    <router-link to="/home">这是跳到home</router-link><br>
    <router-link to="/list">这是跳到list</router-link>
    <router-view></router-view>
  </div>
</template>

<script>

export default {
  name: 'App',
  data() {
    return {
      name: ''
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

6.页面显示

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章