首页 > 其他分享 >手写vue-router核心原理

手写vue-router核心原理

时间:2022-12-07 14:47:05浏览次数:63  
标签:vue parent route Vue import router 手写

最近也在观察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);
  }
};
  • 效果图 效果图

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

标签:vue,parent,route,Vue,import,router,手写
From: https://www.cnblogs.com/hellocoder2029/p/16963002.html

相关文章

  • 创建Vue项目
    前期准备:安装node.js(node-v检查是否安装)安装vue-cli脚手架(使用淘宝镜像,然后运行npminstall-gvue-cli安装脚手架,vue-V检查是否安装)一、基本创建项目操作1、初始......
  • 使用vue深度选择器修改ElementUI组件内样式
    例子:el-collapse标签修改子组件样式在带有scoped属性的style中书写样式时,无法作用影响到子组件中的样式,此时我们会使用到deep深度选择器,来解决此问题,我们在使用less预处理......
  • vscode中引用vue3时红色提示
    从GitHub上下载了一个前端项目学习,用vscode打开。“vue3+vite”在vscode控制台执行npminstall,安装所需要的各种包。这个时候可以用npmrundev,启动项目。但是vs......
  • Vue中的diff算法深度解析
    模板tamplate经过parse,optimize,generate等一些列操作之后,把AST转为renderfunctioncode进而生成虚拟VNode,模板编译阶段基本已经完成了,那么这一章,我们来探讨一下Vue中的一......
  • Vue3必会技巧-自定义Hooks
    Vue3自定义Hooks定义:个人理解:一些可复用的方法像钩子一样挂着,可以随时被引入和调用以实现高内聚低耦合的目标,应该都能算是hook;为什么Vue3要用自定义Hook?:结论:就是为了......
  • Vue3知识点之数据侦测
    Vue的核心之一就是响应式系统,通过侦测数据的变化,来驱动更新视图。实现可响应对象的方式通过可响应对象,实现对数据的侦测,从而告知外界数据变化。实现可响应对象的方式:g......
  • vue源码中的nextTick是怎样实现的
    一、Vue.nextTick内部逻辑在执行initGlobalAPI(Vue)初始化Vue全局API中,这么定义Vue.nextTick。functioninitGlobalAPI(Vue){//...Vue.nextTick=ne......
  • Vue源码解读之InitState
    前面我们讲到了_init函数的执行流程,简单回顾下:初始化生命周期-initLifecycle初始化事件-initEvents初始化渲染函数-initRender调用钩子函数-beforeCreate初始化依赖......
  • 使用vue3在element plus中实现el-table实现拖拽
    1.安装 vuedraggablenpmi-Svuedraggable2.在使用的组件,引入。sortablejs包含在vuedraggableimportSortablefrom"sortablejs"3.row-key必须设置......
  • vue 多级嵌套路由,页面不变化问题解决
      component:{render(c){returnc('router-view')}},redirect:'/set/origin',在二级路由出添加上面的代码,并重定向二级路由页面就可以了......