手写简化版的vue-router

vue-router作为vue全家桶之一的重要插件,有必要去深究一下,今天我们就从0到1手写一个简化版本。

开始之前,我们使用路由插件时是先进行下载路由

npm i vue-router

,然后在main.js中使用app.use导入router插件。想要手写vue-router,必须先搞懂app.use()干了一件什么事情。我们去官方文档下面看看。

app.use()

安装一个插件

  • 类型

    ts
    interface App {
      use(plugin: Plugin, ...options: any[]): this
    }
  • 详细信息

    第一个参数应是插件本身,可选的第二个参数是要传递给插件的选项。

    插件可以是一个带 install() 方法的对象,亦或直接是一个将被用作 install() 方法的函数。插件选项 (app.use() 的第二个参数) 将会传递给插件的 install() 方法。

    若 app.use() 对同一个插件多次调用,该插件只会被安装一次。

两个组件router-view 和router-link

<template>
  <a :href="'#' + props.to">
    <slot></slot>
  </a>
</template>

<script setup>
const props = defineProps({
  to: {
    type: String,
    required: true,
  },
});
</script>

<style lang="css" scoped>
</style>
<!--
 * @LastEditTime: 2024-08-14 10:45:56
 * @Description: file content
-->
<template>
  <component :is="component"></component>
</template>

<script setup>
import { useRouter } from "./index.js";
import { computed } from "vue";
const router = useRouter();
const mapRouter = new Map();
const reflectMapRouter = (router) => {
  router.routes.forEach((route) => {
     // 更具路径进行组件查询,保证O(1)时间
    mapRouter.set(route.path, route.component);
  });
};
//方法执行进行组件注册
reflectMapRouter(router);
//设置为计算属性响应式更新
const component = computed(() => {
  const nowRoute = mapRouter.get(router.current.value);
  //这里注意,需要进行校验,因为用户可能输入错误网址
  return nowRoute ? nowRoute : null;
});
</script>
<style lang="css" scoped>
</style>
/*
 * @LastEditTime: 2024-08-14 10:47:43
 * @Description: file content
 */
import { ref } from "vue";
// 对所有页面暴露
const ROUTER_KEY = "__router__";

export const useRouter = () => {
  //获取暴露的Router对象
  return inject(ROUTER_KEY);
}
class Router {
  constructor(options) {
    //history对象就是createHashWebHistroy返回的history对象
    this.history = options.history;
    // 路由对象数组,path,component,name等配置
    this.routes = options.routes;
    //获取当前路由地址
    this.current = ref(this.history.url);
    // 这里的方法是监听hashchange事件来更新current,切换路由
    //,可以先不看这一段等会会讲
    this.history.bindEvent(() => {
      this.current.value = window.location.hash.slice(1);
    })
  }
  //插件的install方法
  install(app) {
    // 全局声明 有一个router 全局使用的对象
    app.provide(ROUTER_KEY, this);
    //注册全局组件
    app.component('router-link', RouterLink);
    app.component('router-view', RouterView);
  }
}
export const createRouter = (options) => {
  return new Router(options);
}
export const createWebHashHistory = () => {
  function bindEvent(fn) {
    window.addEventListener('hashchange', fn);
  }
  // history 对象
  return {
    url: window.location.hash.slice(1) || '/',
    bindEvent
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weifont

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值