百度面试官:Vue-router源码看过吗?看过的话讲一下你会怎么实现

前言

早期在牛客上看到的一道题,下面是笔者的实现思路~

Vue-router的基本使用

js 复制代码
// index.js
// 本例子为了简化,使用 hash 路由模式
import { createRouter,createWebHashHistory } from 'vuex'

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(),
    routes
})

export default router
js 复制代码
// app.vue
<script setup>

</script>
<template>

<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view/>

</template>
<style> 

</style>
js 复制代码
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'

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

我们就可以完成了一个简单的单页应用。

简单版本的实现

注册两个全局组件

js 复制代码
// index.js
import { inject, ref } from 'vue'
import RouterLink from './RouterLink.vue'
import RouterView from './RouterView.vue'

// 定义一个常量,用于全局访问路由对象
const ROUTER_KEY = '__router__' 

// 返回路由实例
const createRouter = (options) => {
    return new Router(options)
}

// 使得全局可以获取路由对象
const useRouter = () => {
    return inject(ROUTER_KEY)
}

// 返回 hash 模式下的路由历史记录对象
const createWebHashHistory = () => {

}

// 路由类工厂
class Router{
    constructor(options) {

    }
    // 注册路由相关组件和提供全局路由对象
    install(app) {
        // 路由对象,提供给全局访问
        app.provide(ROUTER_KEY, this)
        // 注册全局组件
        app.component('router-link', RouterLink)
        app.component('router-view', RouterView)
    }
}

// 导出模块需要的变量和方法
export {
    useRouter,
    createRouter, // 返回路由实例
    createWebHashHistory // 返回hash 事件监听
}
js 复制代码
// RouterLink.vue
<template>
    <a :href="'#' + props.to">
        <!-- 插槽 -->
        <slot />
    </a>
</template>

<script setup>
import { defineProps } from 'vue'

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

<style scoped>

</style>
js 复制代码
// RouterView.vue
<template>
    <!-- 动态渲染组件 -->
    <component :is="component"></component>
</template>
<script setup>
// 引入 useRouter 和 computed
import { useRouter } from './index' 
import { computed } from 'vue'

// 获取当前路由
const router = useRouter()

// 计算属性 component,根据当前路由找到对应的组件
const component = computed(() => {
    const route = router.routes.find(
        (item) => item.path === router.current.value
    )
    return route ? route.component : null
})
</script>
<style scoped>
   
</style>

RouterLink 组件实现的流程:

  • 通过 props 组件通信的方式传递要重新指向的锚点
  • 通过 a 标签来进行路由的转换
  • 监听了 hashchange 事件,然后进行当前路由信息的更新

RouterView 组件实现的流程:

  • 通过路由信息来获取当前路由的内容
  • 调用 component 组件动态绑定来实现新组件内容的渲染

完善

js 复制代码
import { inject, ref } from 'vue'
import RouterLink from './RouterLink.vue'
import RouterView from './RouterView.vue'

// 定义一个常量,用于全局访问路由对象
const ROUTER_KEY = '__router__' 

// 返回路由实例
const createRouter = (options) => {
    return new Router(options)
}

// 使得全局可以获取定义的路由对象
const useRouter = () => {
    return inject(ROUTER_KEY)
}

// 返回 hash 模式下的路由历史记录对象
const createWebHashHistory = () => {
    // 内部方法,用于绑定事件监听
    function bindEvents(fn) {
        window.addEventListener('hashchange', fn)
    }
    // 返回 hash 值和事件监听的方法
    return {
        bindEvents,
        url: window.location.hash.slice(1) 
    }
}

// 路由类工厂
class Router{
    constructor(options) {
        this.history = options.history  // 路由历史记录对象
        this.routes = options.routes  // 路由的配置数组
        this.current = ref(this.history.url) // 响应式的当前路由,自动更新
        // 给路由历史记录对象绑定事件监听器,当 URL 改变时,更新当前路由值
        this.history.bindEvents(() => {
            this.current.value = window.location.hash.slice(1) // 去除#号
        })
    }
    // 注册路由相关组件和提供全局路由对象
    install(app) {
        // 路由对象,提供给全局访问
        app.provide(ROUTER_KEY, this)
        // 注册全局组件
        app.component('router-link', RouterLink)
        app.component('router-view', RouterView)
    }
}

// 导出模块需要的变量和方法
export {
    useRouter,
    createRouter, // 返回路由实例
    createWebHashHistory // 返回 hash 事件监听
}
相关推荐
海石5 小时前
📱随时随地大小编:TraeSolo 移动端初体验
前端·ai编程·trae
爱滑雪的码农7 小时前
详细说说React大型项目结构以及日常开发核心语法
前端·javascript·react.js
七牛开发者7 小时前
HTML is the new Markdown:来自 Claude Code 团队的实践
前端·人工智能·语言模型·html
@大迁世界8 小时前
43.HTML 事件处理和 React 事件处理有什么区别?
前端·javascript·react.js·html·ecmascript
CloneCello8 小时前
AI时代程序员认知调整指南
前端
ZC跨境爬虫8 小时前
跟着 MDN 学 HTML day_38:(DocumentFragment 文档片段接口详解)
前端·javascript·ui·html·音视频
@大迁世界9 小时前
41.ShadCN 是什么?它如何和 Tailwind CSS 集成,从而更容易构建可访问且可自定义的 React 组件?
前端·javascript·css·react.js·前端框架
千叶风行10 小时前
Text-to-SQL 技术设计与注意事项
前端·人工智能·后端
软件开发技术深度爱好者10 小时前
HTML5+JavaScript读取DOCX 文档完整内容
前端·html5
幽络源小助理11 小时前
苹果CMS V10 MXPro V4.5模版下载, 自适应视频主题源码, 幽络源源码
前端·开源·源码·php源码