简版vue-router实现

253 阅读1分钟
let Vue;
export default class VueRouter {
  constructor(options) {
    this.$options = options;
    // 定义routeMap 实现path到component的映射关系
    this.routeMap = {};
    // 利用vue实现当前路径的响应式,所以vue-router是和vue强耦合只能在vue中使用
    this.app = new Vue({
      data: {
        // 保存当前的值
        current: "/"
      }
    });
  }
  init() {
    // 1.事件监听
    this.bindEvents();
    // 2.创建路由的映射
    this.createRouteMap();
    // 3.声明全局组件
    this.initComponent();
  }
  bindEvents() {
    // 监听hash变化
    window.addEventListener("hashchange", this.onHashChange.bind(this));
    // 监听页面加载
    window.addEventListener("load", this.onHashChange.bind(this));
  }
  onHashChange() {
    this.app.current = window.location.hash.slice(1) || "/";
  }
  // 解析routes选项
  createRouteMap() {
    this.$options.routes.forEach(item => {
      this.routeMap[item.path] = item.component;
    });
  }
  //
  initComponent() {
    // 全局声明组件
    Vue.component("router-link", {
      props: { to: { type: String, required: true } },
      render() {
        // 1. render生成虚拟dom
        // 2. 描述渲染的dom结构
        // h(tag, data, children)
        return <a href={this.to}>{this.$slots.default}</a>; // jsx语法
        // return h("a", { attrs: { href: this.to } }, [this.$slots.default]);
      }
    });
    Vue.component("router-view", {
      render: h => {
        // this 指向VueRouter实例
        const component = this.routeMap[this.app.current];
        return h(component);
      }
    });
  }
}

// 插件要求实现install方法 vue的插件使用的时候都要vue.use() 调用install 并且vue把自己传递进来
VueRouter.install = function(_Vue) {
  Vue = _Vue;
  // 混入:挂载$router
  Vue.mixin({
    beforeCreate() {
      // this 指当前组件的实例
      if (this.$options.router) {
        // 挂载到根组件、子组件创建的时候原型上存在
        Vue.prototype.$router = this.$options.router;
        // 初始化router
        this.$options.router.init();
      }
    }
  });
};