美文网首页
探究vue-router的源码

探究vue-router的源码

作者: 前端的爬行之旅 | 来源:发表于2020-05-13 17:30 被阅读0次

一个vue路由的工作流程


前端路由和后端路由的区别

  • 后端路由
    输入url --> 请求发送到服务器 --> 服务器解析请求的路径 --> 浏览器拿取对应页面 --> 页面渲染
  • 前端路由
    输入url --> js解析地址 --> 找到对应地址的页面 --> 执行页面生成的js --> 页面渲染

vue-router的工作流程

image.png

Hash与History

hash和history的使用

hash:

  • #号后面的就是hash的内容
  • 通过location.hash来获取
  • 通过onhashchange监听hash的改变

history:

  • history即正常的路径
  • 通过location.pathname来获取
  • 通过onpopstate监听history的改变

实现vue-router源码实例


class HistoryRoute {
  constructor(){
    this.current = null;
  }
};
/**
 * options: newRouter时传入的参数;
*/
class VueRouter{
  constructor(options){
    this.mode = options.mode || 'hash';
    this.routes= options.routes || [];
    // 此处可以直接令this.history.current = null;但是为了记录前后路由跳转历史,生成HistoryRoute类
    this.history = new HistoryRoute;
    this.routesMap =  this.creatMap(this.routes);
    this.init(); //初始化路由
  },
  init () {
    // 触发监听事件
    // 改变vue-router中的current变量
    if (this.mode == 'hash') {
      // 根据hash的值自动在url上增加hash
      location.hash ? '': location.hash = '/';
      window.addEventListener('load',() => {
        this.history.current = location.hash.slice(1);
      })
      window.addEventListener('hashchange',() => {
        this.history.current = location.hash.slice(1);
      })
    } else {
      // 根据hash的值自动在url上增加hash
      location.pathname ? '': location.pathname = '/';
      window.addEventListener('load',() => {
        this.history.current = location.pathname;
      })
      window.addEventListener('hashchange',() => {
        this.history.current = location.pathname;
      })
    }
  }
  creatMap(routes){
    // 将routes转化成键值对形式 ‘/’: Hello
    // reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
    // 参数一:初始值, 或者计算结束后的返回值。
    // 参数二:当前元素
    return routes.reduce((memo, current)=> {
      memo[current.path] = current.component;
      return memo
    })
  }
}
VueRouter.install = function (Vue) {
  // 监视current变量的监视者
  Vue.mixin({ //mixin会注入到每个组件
    // 查找到在根实例上放入的VueRouter对象,然后注入到每个组件。
    beforeCreate() {
      // this.$option && this.$options.router:当前这个组件的配置&& 当前组件上已经加载过route路由对象
      if (this.$options && this.$options.router) {
        // 将当前的实例,挂在到当前实例的_root变量上。
        this._root = this;
        // 将当前router 注入到当前实例(组件)的_router上。
        this._router = this.$options.router;
        // 在当前组件this下面中的this._router.history变量上对current进行监听
        Vue.util.defineReactive(this,'current', this._router.history);
      } else {
        // 逐级向上查找是否挂载
        this._root = this.$parent._root;
      }

      // 扩展知识 组件使用this.$router和this.$route
      // 在this上注册$router属性,并且不能更改。
      Object.defineProperty(this, '$router', {
        get () {
          return this._root._router;
        },
      })
      Object.defineProperty(this, '$route', {
        get () {
          return this._root._router.history.current;
        },
      })
    }
  });
  Vue.component('route-view', {
    render(h){
      // 根据当前current获取到对应的路径;
      // _self是vue自带的,_self指向实例自身;
      let current = this._self._root._router.history.current;
      let routeMap = this._self._root._router.routesMap;
      return h(routeMap[current]) //h:渲染作用
    }
  })
}
// 暴露vue类
export default VueRouter;

直接在项目中引入就可以啦!!

相关文章

网友评论

      本文标题:探究vue-router的源码

      本文链接:https://www.haomeiwen.com/subject/caennhtx.html