vue-router 原理简单实现

417 阅读1分钟

官方介绍

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

当然这里要介绍的原理没有那么多功能,只是简单的介绍他的设计的思路,能够理解到这种程度基本上也够用了,想知道更具体的只能看源码实现.

实现思路

  • vue-router在vue中作为插件使用,所以实际上是要实现一个vue的插件
  • url的变化的监听功能
  • 解析路由配置
  • 实现路由组件

要实现一个vue-router主要上面几点,下面看一下如何实现

具体实现

import Vue from 'vue'

//定义一个路由类
class Router {
    constructor(options){
      this.$options = options;
      this.routeMap = {};
      //核心,使用vue数据响应式,来实现路由响应式,路由的变化会驱动模版的重新渲染
      this.app = new Vue({
        data:{
          current:'/'
        }
      })
    }
    init(){//路由初始化
        this.bindEvents();//监听url变化
        this.createRouteMap(this.$options);//解析路由,把路由配置传进去
        this.initComponent();//路由组件
    }
    bindEvents(){
      //监听页面加载时调用
      window.addEventListener('load',this.onHashChange.bind(this));
      //监听路由变化时调用
      window.addEventListener('hashchange',this.onHashChange.bind(this));
    }
    onHashChange(){//取url的hash后面的值,即当前的路由的值
      this.app.current = window.location.hash.slice(1) || '/'
    }
    createRouteMap(options){
      options.routes.forEach(item=>{
        //把传进来的路由配置设置路径和组件对应关系
        this.routeMap[item.path] = item.component;
      })
    }
    initComponent(){//路由组件的实现
      Vue.component("router-link", {
        props: { to: String },
        render(h) {
          return h("a", { attrs: { href: "#" + this.to } }, [
            this.$slots.default//router-link的值
          ]);
        }
      });
      Vue.component("router-view", {
        render: h => {
          const comp = this.routeMap[this.app.current];
          return h(comp);
        }
      });
    }
}

//设置一个vue的router插件
Router.install = function(Vue){
    Vue.mixin({
        beforeCreate(){
            if(this.$options.router){//仅在根组件执行一次
                Vue.prototype.$router = this.$options.router;
                this.$options.router.init();//路由初始化
            }
        }
    })
}

Vue.use(Router)