手打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中较为简单的一部分,要学懂其他的还得再沉淀沉淀...

相关推荐
小菜yh6 分钟前
后端人需知
java·前端·javascript·vue.js·设计模式
周万宁.FoBJ10 分钟前
vue3 实现文本内容超过N行折叠并显示“...展开”组件
开发语言·前端·javascript
Jiaberrr30 分钟前
uniapp视频禁止用户推拽进度条并保留进度条显示的解决方法——方案二
前端·javascript·uni-app·音视频
森叶1 小时前
webpack 的打包target讲解 & node环境打包下的文件存储造成不易察觉的坑点
前端·webpack·node.js
新智元1 小时前
陶哲轩全网悬赏「最强大脑」!AI + 人类颠覆数学难题?凡尔赛网友已下场
前端·人工智能
亿牛云爬虫专家1 小时前
Puppeteer的高级用法:如何在Node.js中实现复杂的Web Scraping
前端·javascript·爬虫·node.js·爬虫代理·puppeteer·代理ip
uhan251 小时前
2024年9月26日 linux笔记
linux·服务器·前端
Jiaberrr2 小时前
uniapp视频禁止用户推拽进度条并保留进度条显示的解决方法——方案一
前端·javascript·微信小程序·uni-app·音视频
慧都小妮子2 小时前
Spire.PDF for .NET【页面设置】演示:设置 PDF 的查看器首选项和缩放系数
前端·pdf·.net·spire.pdf
OEC小胖胖2 小时前
js中正则表达式中【exec】用法深度解读
开发语言·前端·javascript·正则表达式·web