百度面试官: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 事件监听
}
相关推荐
dy17173 小时前
element-plus表格默认展开有子的数据
前端·javascript·vue.js
2501_915918416 小时前
Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
前端·低代码·ios·小程序·uni-app·编辑器·iphone
程序员的世界你不懂7 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
索迪迈科技7 小时前
网络请求库——Axios库深度解析
前端·网络·vue.js·北京百思可瑞教育·百思可瑞教育
在未来等你7 小时前
Kafka面试精讲 Day 13:故障检测与自动恢复
大数据·分布式·面试·kafka·消息队列
gnip7 小时前
JavaScript二叉树相关概念
前端
attitude.x8 小时前
PyTorch 动态图的灵活性与实用技巧
前端·人工智能·深度学习
β添砖java8 小时前
CSS3核心技术
前端·css·css3
空山新雨(大队长)8 小时前
HTML第八课:HTML4和HTML5的区别
前端·html·html5