写点什么

手写 vue-router 核心原理

作者:hellocoder2029
  • 2022-12-07
    浙江
  • 本文字数:2065 字

    阅读完需:约 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>
复制代码

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); }};
复制代码


  • 效果图


好了,今天就玩到这里了,下次再玩别的哈


用户头像

还未添加个人签名 2022-09-08 加入

还未添加个人简介

评论

发布
暂无评论
手写vue-router核心原理_JavaScript_hellocoder2029_InfoQ写作社区