最近也在察看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>
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/cli
npm 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); }};
- 效果图
好了,明天就玩到这里了,下次再玩别的哈