手打Vue-Router小demo

浅聊一下

vue-router想必大家都用的不少,但是你想必是没有看过vue-router的底层源码的,本篇文章将带掘友们来了解一下vue-router到底是怎样来实现的...

进入正题

首先我们使用vite脚手架创建好Vue项目,这里我就不过多赘述...

使用 npm i vue-router@4 在终端下载vue-router

使用vue-router

在src目录下创建文件夹router,添加index.js文件,配置好我们的Home.vue和About.vue

js 复制代码
import {createWebHistory,createRouter} from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'

const routes = [
    {
        path:'/',
        name:'home',
        component:Home
    },
    {
        path:'/about',
        name:'about',
        component:About
    }
]

const router = createRouter({
    history:createWebHashHistory(),//history模式 hash模式
    routes
})

export default router

抛出router以后,在main.js中需要引入并且use掉

js 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App)
.use(router)
.mount('#app')

再在App.vue中使用路由,实现路由跳转

js 复制代码
<template>
  <div class="nav">
   <router-link to="/">Home | </router-link>
   <router-link to="/about">About</router-link>
  </div>
  <router-view />
</template>

<script setup>

</script>

<style lang="css" scoped>

</style>

点击Home去到home页面,点击About去到about页面

接下来,我们将不使用我们下载的vue-router,而是自己手敲一个vue-router,实现页面跳转

使用myRouter

在敲代码之前,先来观察一下我们需要写点什么

js 复制代码
import {createWebHashHistory,createRouter} from './myRouter'
import Home from '../views/Home.vue'
import About from '../views/About.vue'

const routes = [
    {
        path:'/',
        name:'home',
        component:Home
    },
    {
        path:'/about',
        name:'about',
        component:About
    }
]

const router = createRouter({
    history:createWebHashHistory(),//history模式 hash模式
    routes
})

export default router

引入中,我们从myRouter引入了 createWebHashHistory和createRouter

createRouter( )

不难看出,我们这里是在创建一个router的实例对象

js 复制代码
const router = createRouter({
    history:createWebHashHistory(),//history模式 hash模式
    routes
})

所以,createRouter()的返回值是一个Router对象,那么,createRouter()方法就该这么写

js 复制代码
function createRouter(options) {
  return new Router(options)
}

此时我们还暂未定义Router对象,所以再来定义一下

js 复制代码
class Router {
  constructor(options) {
    this.history = options.history
    this.routes = options.routes
    this.current = ref(this.history.url)  // 当前路径

    this.history.bindEvents(() => {
      this.current.value = window.location.hash.slice(1)
    })
  }
  install(app) {
    console.log(app);
    app.provide(ROUTER_KEY, this)
    // 注册全局组件router-link
    app.component('router-link', RouterLink)
    app.component('router-view', RouterView)
  }
}

这里使用的是ES6的语法,使用constructor来创建类,其中的参数由前面createRouter()中传入的值可以知道是一个history,一个routes,并且我们还要知道当前的url是什么才可以跳转,所以还有一个current。那么这个bindEvents是个干什么用的呢?这个待会再讲,先来看看下面那一坨install()是干什么用的...

我们在index.js中抛出了一个router对象,在main.js中引入并且use掉vue-router才能正常工作,那么是什么阿猫阿狗都能被use的吗?当然不行,vue规定了,只有有install()的才可以被use,我们可以在install()中注册全局组件,里面的'router-link'router-view就是全局组件,

createWebHashHistory( )

createHashHistory( )主要是返回一个当前的url

js 复制代码
function createWebHashHistory() {
  function bindEvents(fn) {
    window.addEventListener('hashchange', fn)
  }
  return {
    bindEvents,
    url: window.location.hash.slice(1) || '/'
  }
}

bindEvents接收一个回调函数,一旦url的地址改变,就触发回调函数,createHashHistory( )返回了bindEvents方法和url,然后在Router中调用

js 复制代码
this.history.bindEvents(() => { 
    this.current.value = window.location.hash.slice(1) 
})

一旦url发生变化,立马更新当前的current

useRouter( )

在useRouter中返回了一个inject,他和provide是一对父子传值组件

provide 是一个在父组件中调用的方法,用于提供数据给后代组件。它接收两个参数,key 是一个唯一的标识符,用于区分不同的提供者,value 则是要提供给后代组件的值。我们需要在前面定义一个key

js 复制代码
const ROUTER_KEY = '_router_'

inject 是一个在子组件中调用的方法,用于从父组件中获取提供的数据。它接收两个参数,key 是要获取的数据的标识符,defaultValue 是当未找到对应的提供者时的默认值。

js 复制代码
function useRouter() {
  return inject(ROUTER_KEY)
}

在前面的例子里,要让页面跳转,我们得放上<router-link />,这是一个全局组件,我们来看看他怎么写的...

html 复制代码
<template>
    <a :href="'#'+to">
      <slot />
    </a>
  </template>
  
  <script setup>
  defineProps({
    to: {
      type: String,
      required: true
    }
  })
  </script>

实际上router-view的底层就是a标签,require为true要求必须传入一个String类型的值作为跳转路径,使用插槽来添加想要的内容

router-view

要想让页面显示,就得先放上<router-link />,这又是怎么实现的呢?

js 复制代码
<template>
  <component :is="component"></component>
</template>

<script setup>
import { computed } from 'vue';
import { useRouter } from '../myRouter/index.js'
const router = useRouter() // 在当前组件注入了router
const component = computed(() => {
 
  // 如果当前的url是'/',就返回Home.vue
  const route = router.routes.find((route) => {
    return route.path === router.current.value
  })
  return route ? route.component : null
})
</script>

通过 :is 属性将 component 变量绑定到 <component> 标签上,这样就可以根据 component 的值动态渲染不同的组件。

<script setup> 中,首先导入了 computed 和自定义的 useRouter 函数。然后通过 useRouter() 获取到一个路由实例 router

接下来,定义了一个计算属性 component,它使用 computed 函数来计算动态组件的值。计算属性的逻辑是根据当前的路由路径从 router.routes 中找到对应的路由对象 route,然后返回该路由对象的 component 属性值。

在这段代码中, router.routes 是一个包含了所有路由信息的数组,每个路由对象都有 pathcomponent 属性。通过遍历 router.routes,找到与当前路由路径相匹配的路由对象,并获取其 component 属性,用于动态渲染组件。

最后,将计算属性 component 绑定到 <component> 标签的 :is 属性上,使得组件能够根据 component 的值动态渲染不同的组件。

到此一个简单的vue-router就完成了...

结尾

Vue-Router的源码是vue中较为简单的一部分,要学懂其他的还得再沉淀沉淀...

相关推荐
中微子5 分钟前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上102420 分钟前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y36 分钟前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁43 分钟前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry43 分钟前
Fetch 笔记
前端·javascript
拾光拾趣录44 分钟前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟1 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan1 小时前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson1 小时前
青苔漫染待客迟
前端·设计模式·架构
写不出来就跑路1 小时前
基于 Vue 3 的智能聊天界面实现:从 UI 到流式响应全解析
前端·vue.js·ui