打造属于你的 Vue Router:手写实现核心原理,一次搞懂前端路由!
2025-05-05 08:51 阅读(52)

Vue Router 是 Vue.js 应用中用于管理页面导航的核心工具,它提供了简洁的 API 和强大的功能,帮助开发者轻松实现前端路由。在这篇文章中,我们将一步步手写一个 Vue-Router 实现,覆盖核心概念和功能。主要包括 router 的初始化与配置、router-link 和 router-view 的实现,以及一些 Vue 组件的知识。

Vue 组件与插件机制

在手写之前,先了解几个概念

全局组件

在 Vue 中,我们可以使用 app.component 注册全局组件,任何地方都可以直接访问:

app.component('my-component', MyComponent)

如果未注册全局组件,Vue 会把它当作普通的 HTML 标签处理。

插槽与组件复用性

Vue 的插槽功能让我们能够在组件内部定义动态内容。在 router-link 的实现中,我们通过 <slot></slot> 插槽允许用户自定义链接的展示文本或 HTML 元素。

Router 插件与 Vue 的结合

Vue 通过插件机制可以将第三方库或插件整合到 Vue 应用中。使用 app.use(router),实际上是调用 Router 实例的 install 方法,这个方法将 Router 实例挂载到 Vue 应用中,并注册了全局的 router-link 和 router-view 组件。

Vue-Router 的初始化与配置

Vue-Router 是 Vue.js 生态中的一个路由管理工具,它让开发者可以轻松管理应用中的不同页面,基于路径加载不同的组件。下面是我们自定义一个 Vue-Router 的基本步骤。

创建路由

我们首先定义一个工厂函数 createRouter,通过它创建一个路由实例:

export const createRouter = (options) => {
    return new Router(options)
}

createRouter 函数接收 options 参数,并返回一个新的 Router 实例。Vue Router 的初始化是通过 createRouter 函数完成的,而不是直接 new Router。这是因为在 Vue 3 中,推荐的做法是通过工厂函数来创建实例,而不是直接使用类的构造函数。这种设计模式可以确保每次创建的 Router 实例都是独立的,避免出现全局状态被共享的问题。

配置 History 模式

Vue-Router 支持不同的路由模式:hash 模式和 history 模式。这里我们手写一个简单的 hash 模式实现:

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

createWebHashHistory 返回一个包含 url 和 bindEvents 的对象,其中 url 是当前的 hash 路径,bindEvents 用于监听 URL 的变化。

Router 类实现

接下来,我们定义一个 Router 类,来处理路由的核心逻辑:

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) {
        app.provide('__router__', this)
        app.component('router-link', RouterLink)
        app.component('router-view', RouterView)
    }
}

this.history:负责管理 URL 状态。

this.routes:存储路由配置信息。

this.current:表示当前的路径,是一个响应式变量,利用 ref 创建。

install(app):通过 app.provide 将 Router 实例注入到应用上下文中,并注册了 router-link 和 router-view 两个全局组件。


全局注入与插件系统

Vue.js 的插件系统通过 app.use() 来使用。我们将路由通过 provide/inject 机制提供给整个应用:

export const useRouter = () => {
    return inject('__router__')
}

useRouter 是一个自定义的 Hook,利用 Vue 的 inject 获取我们上面通过app.provide('__router__', this)全局提供的 router 对象。

router-link 和 router-view 实现

接下来我们实现路由的核心组件——router-link 和 router-view。

router-link

router-link 是一个全局组件,负责生成链接,允许用户导航到不同页面。我们实现如下:

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

<script setup>
defineProps({
    to: {
        type: String,
        required: true
    }
})
</script>

href:基于 to 属性生成 hash 地址。

<slot>:使用插槽允许用户自定义链接的内容。


router-view

router-view 是另一个全局组件,负责渲染当前路径对应的组件。核心思想是利用 Vue 的动态组件机制 <component :is="component">。实现如下:


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

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

const router = useRouter()

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

component:是一个动态组件,根据当前 URL 渲染不同的组件。

computed:监听当前路径的变化,找到匹配的路由配置并返回相应的组件。

总结

虽然手写的实现较为基础,但它帮助我们深入理解了 Vue-Router 的基本工作原理。


使用方法:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)


// vue和它生态的对接
app.use(router)
    .mount('#app')

import { createRouter,createWebHashHistory } from './grouter/index'
import Home from '../pages/Home.vue'
import About from '../pages/About.vue'

const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        // component: () => import('../pages/About.vue')
        component: About
    }
]

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

export default router
<template>
  <div>
    <header>
      <nav>
        <RouterLink to="/">首页</RouterLink>
        <RouterLink to="/about">about</RouterLink>
      </nav>
    </header>
    <main>
    <router-view></router-view>
    </main>
    <footer>

    </footer>
  </div>
</template>

<script setup>
import RouterLink from './router/grouter/RouterLink.vue';


</script>

<style lang="css" scoped>

</style>

如果你觉得这篇文章对你有帮助,欢迎点赞并关注!


https://www.zuocode.com