手写 vue-router 核心原理
- 2022 年 9 月 26 日 浙江
本文字数:2061 字
阅读完需:约 7 分钟
最近也在观察 vue3 新特性,抽空玩一玩嵌套路由的 vue-router,直接上代码
代码展示
app.vue
<template> <div id="app"> <div> <router-link to="/">Index</router-link> | <router-link to="/person">Person</router-link> | <router-link to="/person/info">PersonInfo</router-link> </div> <!-- 一级路由 --> <router-view /> </div></template>
<style>#app{ display: flex; flex-direction: column; align-items: center;}</style>
复制代码
Index.vue
<template> <div class="index"> <h1>this is index page</h1> </div></template>
复制代码
Person.vue
<template> <div class="person"> <h1>this is person page</h1> <!-- 二级路由 --> <router-view /> </div></template>
复制代码
PersonInfo.vue
<template> <div class="personInfo"> <h2>this is personInfo page</h2> </div></template>
复制代码
vue 全家桶视频讲解:进入学习
js 文件
main.js
import Vue from 'vue'import App from './App.vue'import router from './router'
new Vue({ router, render: h => h(App)}).$mount('#app')
复制代码
babel.config.js
需要添加 babel 依赖支持新语法,如可选链
npm install --save-dev @babel/core @babel/clinpm install --save-dev @babel/plugin-proposal-optional-chaining
module.exports = { presets: [ '@babel/preset-env' ], plugins: ['@babel/plugin-proposal-optional-chaining']}
复制代码
router 目录下文件
index.js
import Vue from "vue";import VueRouter from "./vue-router";import Index from "../views/Index.vue";import Person from "../views/Person.vue";import PersonInfo from "../views/PersonInfo.vue";
Vue.use(VueRouter);
const routes = [ { path: "/", name: "Index", component: Index }, { path: "/person", name: "Person", component: Person, children:[ { path: "/person/info", name: "PersonInfo", component: PersonInfo } ] }];
const router = new VueRouter({ routes});
export default router;
复制代码
vue-router.js 这里先借助 Vue 的工具
Vue.util.defineReactive实现数据响应式,后续再手撕这个库
import routerLink from "./router-link";import routerView from "./router-view";
let Vue;class VueRouter { constructor(options) { this.$options = options
this.current = window.location.hash.slice(1) || "/"
// 设置响应式数组数据 Vue.util.defineReactive(this, "routerArray", [])
// 监听hash值变化 window.addEventListener("hashchange", this.hashChange.bind(this))
this.getRouterArray() }
hashChange() { this.current = window.location.hash.slice(1) || "/" this.routerArray = [] this.getRouterArray() }
getRouterArray(routes) { routes = routes || this.$options.routes for (const route of routes) { if (this.current === '/' && route.path === '/') { this.routerArray.push(route) return }
if (this.current.indexOf(route.path) !== -1 && route.path !== '/') { this.routerArray.push(route) if (route.children) { // 递归子路由 this.getRouterArray(route.children) } return } } }}
VueRouter.install = function(_Vue) { Vue = _Vue
// Vue全局混入,等new Vue中的router实例创建之后挂载到Vue上 Vue.mixin({ beforeCreate() { if (this.$options.router) { Vue.prototype.$router = this.$options.router } }, });
// 注册router-link和router-view全局组件 Vue.component("router-link", routerLink) Vue.component("router-view", routerView)}
export default VueRouter
复制代码
router-link.js
export default { props: { to: { type: String, required: true } }, render(h) { return h( "a", { attrs: { href: "#" + this.to, }, }, this.$slots.default ); }};
复制代码
router-view.js
export default { render(h) { // 设置嵌套路由标识 this.$vnode.data.rv = true
// 嵌套路由设置深度 let depth = 0 let parent = this.$parent while (parent) {
// 上级还有嵌套路由标识rv为true的,深度加一 if (parent.$vnode?.data?.rv) { depth++ } parent = parent.$parent }
// 简单处理 const route = this.$router.routerArray[depth] return h(route?.component); }};
复制代码
效果图
好了,今天就玩到这里了,下次再玩别的哈
划线
评论
复制
发布于: 刚刚阅读数: 3
还未添加个人签名 2022.09.08 加入
还未添加个人简介










评论