手写一个简单的vue-router 手写vue源码

123 阅读2分钟

分析源码

import { createRouter, createWebHashHistory,createWebHistory } from 'vue-router'

const route = []

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

export default router

从源码来看我们要手写一个路由主要就是要实现一个createRouter方法和一个createWebHashHistory方法或者createWebHistory方法,我们这边选择实现createWebHashHistory,最后能够让路径和组件能够一一映射,一个简单的路由就算实现了。

createRouter

const ROUTER_KEY = '_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_KEY, this)
        // 注册全局组件router-link
        app.component('router-link', RouterLink)// 声明全局组件
        app.component('router-view', RouterView)
    }
}

export function createRouter(options) {
    return new Router(options)
}

首先是createRouter(),我们用一个class。我们知道我们调用createRouter()时需要传入一个对象,里面有两个值,一个是routes数组,另外一个是history。我们在构造时就根据这个结构去构造。
路由的跳转是根据浏览器的url地址进行的,所以我们在此将他存下来并且赋值为一个响应式的属性,方便在url地址变化时及时做出相应的变化。
然后要调用掉history里面的一个方法,这个方法是获取当前地址。
这个install(app)就单纯是因为只有install之后的才能够被vue给use掉。app.component()是注册为全局组件,这个就是我们自己的router-viewrouter-link

useRouter

export function useRouter() {
    return inject(ROUTER_KEY)
}

注入路由,就是得到了整个Router类。

RouterView

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

<script setup>
import { computed } from 'vue';
import { useRouter } from '../myRouter';
const router = useRouter(); // 在当前组件注入了router

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

RouterView 的作用就是从routes数组中根据你当前的url启用相应的代码,首先就是在得到useRouter的结果也就是整个Router类,我们需要根据这个得到routes数组。然后就是根据当前的url去找对应的组件,并且放进对应的位置。

RouterLink

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

<script setup>

defineProps({
    to: {
        String,
        required: true
    }
})
</script>
<style lang="css" scoped></style>

RouterLink其实就是一个a标签,动态绑定了一个to属性,根据这个to属性跳往对应的url地址。

createWebHashHistory()

export function createWebHashHistory() {
    function bindEvents(fn) {
        window.addEventListener('hashchange', fn)//监听浏览器地址改变事件
    }
    return {
        bindEvents,
        url: window.location.hash.slice(1) || '/'// 获取当前地址
    }
}

createWebHashHistory()就是要持续的获取当前的url地址并返回出去。


假如您也和我一样,在准备春招。欢迎加我微信shunwuyu,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!