vue-router作为vue全家桶之一的重要插件,有必要去深究一下,今天我们就从0到1手写一个简化版本。
开始之前,我们使用路由插件时是先进行下载路由
npm i vue-router
,然后在main.js
中使用app.use
导入router
插件。想要手写vue-router
,必须先搞懂app.use()
干了一件什么事情。我们去官方文档下面看看。
app.use()
安装一个插件。
-
类型
tsinterface 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
}
}