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