2021-01-02 Vue-router插件简单原理实现

2021-01-02 Vue-router插件简单原理实现

Vue-router官方介绍

Vue-Router是Vue.js官方的路由管理器
安装:vue add router
使用步骤:

  1. 使用vue-router插件,router.js

    import Router from 'vue-router'
    Vue.use(Router)
    
  2. 创建Router实例,router.js

    export default new Router({...})
    
  3. 在根组件上添加该实例,main.js

    import router from './router'
    new Vue({
    	router,
    }).$mount('#app')
    
  4. 添加路由视图,导航,App.vue

    <router-view></router-view>
    <router-link to="/">Home</>
    this.$router.push('/')
    

Vue-router源码实现

问题分析:
单页面应用程序中,url发生变化时,不能刷新页面,不能调后段接口,做的是前端路由,所以采用hash和history api两种前端路由模式

根据url显示对应的内容router-view是一个全局组件,数据也要是响应式的,current变量持有url地址一旦发生变化,动态执行render函数

实现一个插件:
一:实现一个VueRouter类

  • 处理路由选项
  • 监听url变化,hashchange
  • 响应这个变化

二:实现install方法

  • $router注册
  • 两个全局组件

思考三个问题:
1、router是个插件,做了什么事
2、在根实例,挂载了一下router,为什么
3、router-view router-link为啥可以直接用

/**
 * 自己的路由器
 * 1、VueRouter类,是一个插件
 */
let Vue; // 引用构造函数,VueRouter中要使用

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

    // 提前缓存path和route映射关系
    this.routeMap = {};
    this.$options.routes.forEach(route => {
      this.routeMap[route.path] = route;
    });

    // 声明一个响应式的current
    // 渲染函数如果要重复执行,必须依赖于响应式数据
    const initial = window.location.hash.slice(1) || "/";
    Vue.util.defineReactive(this, "current", initial);

    // 监听url变化
    window.addEventListener("hashchange", () => {
      this.current = window.location.hash.slice(1);
      //   console.log(this.current);
    });
  }
}

// 插件要实现install方法
// 参数1就是Vue
VueRouter.install = function(_Vue) {
  // 保存构造函数的引用
  Vue = _Vue;

  // console.log(this);

  // 2、挂载$router到Vue原型
  // 利用全局混入,延迟执行下面的代码,这样可以获取router实例,就是new Vue({router参数})
  Vue.mixin({
    beforeCreate() {
      // this指向组件实例
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router;
      }
    }
  });

  // 3、声明两个全局组件router-view,router-link
  // <router-link to="/abc"></router-link>
  Vue.component("router-link", {
    props: {
      to: {
        type: String,
        required: true
      }
    },
    render(h) {
      // <a href="#/abc">xxx</a>
      // this指向当前组件实例
      return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
    }
  });
  Vue.component("router-view", {
    render(h) {
      // current
      // 动态获取对应组件
      /* let component = null;
      const route = this.$router.$options.routes.find(
        route => route.path === this.$router.current
      );
      if (route) component = route.component; */
      const { routeMap, current } = this.$router;
      const component = routeMap[current] ? routeMap[current].component : null;
      return h(component);
    }
  });
};

export default VueRouter;

关于嵌套路由,后面补充…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值