vue系列--实现一个简单的vue-router

一个简单的vue的路由实现

首先要确定我们要做的功能点
VueRouter是一个插件,要有install方法
要实现router-view和router-link两个组件
要监听url的变化,hash模式要监听hashchange事件,history模式要监听popstate事件
实现根据不同的路由变化显示不同的组件

1. 声明类

class SimpleVueRouter {}

2. 注册install方法,接收Vue类

SimpleVueRouter.install = function(_Vue) {
  // Vue是js内部的变量,_Vue是真正的Vue类
  Vue = _Vue;
}

3. 写SimpleVueRouter的构造函数,保存传进来的路由配置options,声明一个路由对应关系,声明一个Vue的实例对象用于响应式


class SimpleVueRouter {
  constructor(options) {
    this.$options = options;

    this.routeMap = {};

    this.app = new Vue({
      data() {
        return {
          current: '/'
        }
      }
    });
  }
}

4. 在SimpleVueRouter类里新增init方法,在install方法里给Vue注册mixin,给Vue加上$router和执行init方法

为什么要使用mixins,因为我们需要把VueRouter的实例对象挂载在当前Vue的实例上,但是在Vue.use的时候,实例对象还没有生成,必须要在实例对象已经生成了才行,所以注册一个全局的mixin,便于初始化的时候挂载VueRouter实例

// 添加install方法,在Vue.use的时候会执行
SimpleVueRouter.install = function(_Vue) {
  Vue = _Vue;
  Vue.mixin({
    beforeCreate() {
      /**
       * this是Vue的实例对象
       * this.$options是new Vue()的时候传入的参数
       * 只有main.js才会有router这个项,所以if只会进入一次
       *  */ 
      if (this.$options.router) {
        this.$router = this.$options.router;
        this.$options.router.init();
      }
    }
  });
}

5. 监听浏览器的hashChange和load方法事件,当监听到的时候,修改this.app.current

  initEvent() {
    // 监听浏览器的hashchange和load事件,使用bind改变this指向
    window.addEventListener('hashchange', this.handleHashChange.bind(this));
    window.addEventListener('load', this.handleHashChange.bind(this));
  }

  handleHashChange() {
    // 获取#后面的部分赋值给app的current
    this.app.current = location.hash.slice(1);
  }

6. 注册路由对应关系

  initRouteMap() {
    this.$options.routes.forEach(item => {
      this.routeMap[item.path] = item;
    });
  }

7. 注册s-router-link和s-router-view组件

  registerComponents() {
    // router-link默认展示a标签,用于点击跳转
    Vue.component('s-router-link', {
      props: {
        to: String,
        required: true,
      },
      render: function (h) {
        return h('a', { attrs: { href: `#${this.to}` } }, this.$slots.default);
      }
    });

    // router-view是一个容器,展示当前路由对应组件即可
    Vue.component('s-router-view', {
      render: h => {
        // 此处使用箭头函数,为了让this指向当前router实例而不是vue实例
        const com = this.routeMap[this.app.current].component;
        return h(com)
      }
    });
  }

8. 在init方法里分别初始化事件、路由和组件

init() {
    this.initEvent();
    this.initRouteMap();
    this.registerComponents();
  }

9. 使用方法

import SimpleVueRouter from './simple-vue-router';
import Vue from 'vue';
import Com1 from './components/com1';
import Com2 from './components/com2';
import Home from './components/home';

Vue.use(SimpleVueRouter);

export default new SimpleVueRouter({
  routes: [{
    path: '/',
    component: Home
  }, {
    path: '/com1',
    component: Com1
  }, {
    path: '/com2',
    component: Com2
  }]
});





整个思路流程就是,注册插件,监听浏览器的hash改变事件,当hash改变的时候,修改某个vue实例的某个属性,利用vue的响应式,使用到的地方也会改变,从而去更新router-view显示的地方

需要准备的知识包括:

  • 如何注册Vue插件
  • 如何注册组件
  • Vue的mixin
  • render函数的用法

本例只实现了使用hash的方式的实现简单的路由跳转和显示,其他方法读者有兴趣的话可以自己实现

github地址

你可能感兴趣的:(vue系列--实现一个简单的vue-router)