likes
comments
collection
share

手搓迷你Vue Router:当“路由”遇见“代码料理”

作者站长头像
站长
· 阅读数 27

在现代Web开发中,尤其是构建单页面应用程序(SPA),Vue Router 成为了连接视图和路由逻辑的关键桥梁。本文将通过手搓一个简易版的Vue Router,帮助我们理解其核心原理和工作机制。我们将从创建路由器实例定义路由历史模式实现路由组件和钩子,以及使用自定义路由组件几个关键方面展开。

手搓迷你Vue Router:当“路由”遇见“代码料理”

一、创建路由器实例

首先,我们定义一个createRouter函数,它接受路由选项并返回一个Router类的实例。Router类负责处理路由状态事件绑定

// 单例的责任
export const createRouter = (options) => {
    return  new Router(options)
}

const ROUTER_KEY = '__router__'

export const useRouter = () => {
    return inject(ROUTER_KEY)
}

class Router {
    constructor(options) {
        this.history = options.history
        this.routes = options.routes
        this.current = ref(this.history.url)
        this.history.bindEvents(() => {
            // console.log('//////////')
            this.current.value = window.location.hash.slice(1)
        })
    }
    // use 调用 插件install
    install(app) {
        // 全局声明有一个router 全局使用的对象
        app.provide(ROUTER_KEY,this)
        console.log('准备与vue 对接', app)
        app.component('router-link', RouterLink)
        app.component('router-view', RouterView)
    }
}

这段代码定义了一个简单的单例模式的路由系统,用于Vue应用中。下面是关键点的简要解析:

  1. createRouter 函数:

    • 这是一个工厂函数,接受配置选项并返回一个新的 Router 实例。
    • 它确保了在整个应用程序中,路由管理器只有一个实例。
  2. useRouter 函数:

    • 这个函数用于在组件中获取路由实例。
    • 它使用 Vue 的 inject 方法来访问在父组件或应用根注入的路由器实例。
  3. Router:

    • constructor: 构造函数接收一个配置对象,包含历史记录(history)和路由规则(routes)。
    • this.history 和 this.routes 分别存储了历史记录和路由规则。
    • this.current 是一个响应式引用(ref),存储当前URL路径。
    • bindEvents 方法绑定事件监听器,当URL变化时更新 current 的值。
  4. install 方法:

    • 当这个方法被调用时,它将 Router 实例注入到 Vue 应用中,使得任何组件都可以通过 useRouter 访问它。
    • 它还注册了两个全局组件:router-link 和 router-view,用于导航和渲染匹配的组件。
  5. 全局组件:

    • RouterLink 组件通常用于创建链接,可以导航至不同的路由。
    • RouterView 组件则用于渲染与当前活动路由相匹配的组件。

这个路由系统遵循了单例设计模式,并与 Vue 的响应式系统和组件系统集成,以实现动态路由和视图切换。

二、定义路由历史模式

接下来,我们实现两种路由历史模式:哈希模式和历史模式。此处仅展示哈希模式的实现:

export const createWebHashHistory = () => {
    function bindEvents(fn) {
        window.addEventListener('hashchange', fn)
    }
    // history 对象
    return {
        url: window.location.hash.slice(1) || '/',
        bindEvents
    }
}

这段代码定义了一个名为 createWebHashHistory 的函数,用于创建基于浏览器 hash历史记录对象,这是前端单页应用中常见的路由管理方式之一。以下是关键点解析:

  1. bindEvents 函数:

    • 这是一个内部函数,用于绑定 hashchange 事件到指定的回调函数 fn
    • 当浏览器地址栏的 hash 发生变化时,这个事件会被触发,从而允许你更新应用状态或重新渲染页面。
  2. 返回的对象:

    • 返回一个对象,该对象有两个属性:

      • url: 初始化为当前浏览器 URL 中的 hash 值(如果存在的话),如果没有 hash,则默认为 '/'
      • bindEvents: 这是上述定义的 bindEvents 函数,用于外部代码监听 hashchange 事件。

总结来说,createWebHashHistory 创建了一个封装了浏览器 hash 变化监听功能的对象,这个对象可以被路由系统用来监控 URL hash 的变化,从而触发相应的路由逻辑。

三、实现路由组件和钩子

1.为了使路由组件能在Vue应用中使用,我们需要定义RouterLinkRouterView组件。下面展示了RouterLink的基本实现:

<template>
    <a :href="'#' + props.to">
        <slot />
    </a>
</template>

<script setup>
import { defineProps} from 'vue'
const props = defineProps({
    to: {
        type: String,
        required: true
    }
})
</script>

这段代码展示了如何在 Vue 3 中创建一个 <router-link> 组件的简化版本。下面是关键点的简要解析:

  1. 模板 (template) :

    • 使用 <a> 标签作为基础元素来构建链接。
    • 动态绑定 href 属性,值为 '#' 加上 props.to 的值,这会改变浏览器地址栏的 hash 部分而不触发页面刷新,适合基于 hash 的路由系统。
  2. 脚本 (script setup) :

    • 使用 Vue 3 的 Composition API 和 defineProps 函数来定义组件的属性。
    • props 对象接收一个 to 属性,其类型为字符串且是必需的,表示链接的目标路由路径。

小结:

  • 这个组件接收一个 to 属性,用于指定链接的路由目标。
  • 它使用 <a> 标签并通过修改 href 属性值来创建一个指向特定 hash 的链接,这通常用于单页应用的客户端路由。
  • 组件内部使用了 Vue 3 的 Composition API,使代码更简洁、易于理解和维护。

2.RouterView组件用于动态渲染当前路由匹配的组件:

<template>
    <component :is="component"></component>
</template>

<script setup>
import { useRouter } from './index.js'
import { computed } from 'vue'

const router = useRouter();
console.log(router)

const component = computed(() => {
    const route = router.routes.find(
        (route) => route.path == router.current.value
    )
    console.log(route,'??????//////')
    return route? route.component:null
})
</script>

这段代码展示了一个简单的 Vue 3 组件,它的作用是在当前活动的路由路径下渲染相应的组件。下面是关键点的解析:

  1. 模板 (template) :

    • 使用 <component> 标签,并通过 :is 绑定动态组件名,这样可以根据计算属性 component 的值来渲染不同的组件。
  2. 脚本 (script setup) :

    • 引入 useRouter 和 computed
    • 通过 useRouter 获取路由实例,这允许组件访问到路由相关的数据和方法。
    • 定义 component 计算属性,用于决定当前应渲染哪个组件。
      • 遍历 router.routes 数组寻找与 router.current.value 匹配的路由路径。
      • 如果找到匹配的路由,则返回对应的组件;否则返回 null

小结:

  • 组件通过 :is 动态地决定渲染哪个子组件,这是 Vue 中动态组件的用法。
  • component 计算属性确保每次路由变化时都能正确渲染与当前路由路径匹配的组件。
  • 这种设计模式常用于 Vue 应用中的 <router-view> 组件,负责根据当前激活的路由显示正确的组件。

四、使用自定义路由组件

最后,我们需要在主应用中注册和使用这些自定义组件:

import { createRouter, createWebHashHistory } from './grouter/index'

const routes = [
    // 定义你的路由规则
]

const router = createRouter({
    history: createWebHashHistory(),
    routes
})

export default router
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'

const app = createApp(App)
app.use(router)
    .mount('#app')

这段代码展示了如何在 Vue.js 应用中设置和使用路由。以下是关键点的简要解析:

  1. 创建路由器:

    • 从 ./grouter/index 导入 createRouter 和 createWebHashHistory
    • 定义路由规则数组 routes
    • 使用 createRouter 函数创建路由器实例,传入配置对象,包括使用 createWebHashHistory 创建的历史记录对象和路由规则。
  2. 导出路由器:

    • 将创建的 router 实例导出,以便在应用的其他部分使用。
  3. 初始化 Vue 应用:

    • 从 Vue.js 导入 createApp 函数。
    • 导入根组件 App.vue 和上面创建的 router
    • 使用 createApp 创建应用实例,传入根组件 App
    • 使用 .use(router) 方法将创建的路由器实例安装到应用中。
  4. 挂载应用:

    • 使用 .mount('#app') 方法将应用挂载到 DOM 中具有 id app 的元素上。

小结:

  • 这段代码配置了 Vue.js 的路由功能,使用基于 hash 的历史记录机制。
  • 路由器实例通过 createRouter 和路由规则数组创建。
  • 应用实例通过 createApp 创建,并使用 .use() 方法将路由器实例注入应用上下文。
  • 最后,应用挂载到 DOM 上,完成整个应用的初始化过程。

五、总结

手写一个简易版的Vue Router不仅加深了我们对前端路由系统的理解,还揭示了Vue Router背后的工作机制。通过定义路由实例、历史模式、组件和钩子,我们可以构建出灵活且可扩展的路由系统,为SPA的开发奠定坚实的基础。

转载自:https://juejin.cn/post/7392248233194111012
评论
请登录