理解 vue 的 use ,手写 router

前言

先随便聊聊 vue-router 中的一些知识点,一些考点。

  • router 初始化以及配置,就不过多赘述,但自己要牢记于心。

  • 前几天和大家提到的 路由守卫, 比如router.brforeEach 等一些常用的api。

  • 路由懒加载。

css 复制代码
{
  path: '/about',
  component: () => import('./views/About.vue')
}

进行路由匹配的时候,这样使用 import 函数引入,只有匹配到才会进行加载,可以更快的看到首页。所以首页就需要直接在外边 import 关键字导入。

  • router-link router-view 。点击 router-link 后,可以跳到其他页面,好像和 a 标签一样。但是它可比 a 强多了,是个组件。router-view 也是个组件,根据相应的路由地址,把对应的组件显示到自己所在的位置。

它们两个是全局组件,但不是 vue 自带的,是需要在 main.js 中 .use 一下才可以使用。这个 .use 到底是怎么回事?今天就来一起看看。

基本准备

1. 项目搭建

xml 复制代码
<!-- about页面 -->
<template>
    <div>
        about
    </div>
</template>

<!-- home页面 -->
<template>
    <div>
        home
    </div>
</template>

创建页面级别的组件 Home.vue 以及 About.vue,写入这样一个简单的内容。

接着就是基本的创建 router文件夹下的 index.js 来配置这两个组件的路由,About 记得使用懒加载,这里不写出来了。

xml 复制代码
<template>
  <header>
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
  </header>
  <main>
    <router-view></router-view>
  </main>
</template>

最后在 App.vue 中用起来就行。

2. 了解 vue 组件

思考 router-link 组件是如何工作的呢?像 router -link 这样不需要引入的组件称为 全局组件 ,注册后可在任何地方直接访问。除了这个还有我们最熟悉的 自定义组件 ,就是我们一般会写在 components 文件夹下的一些组件,需要什么,写一个就行,但是需要显式引入并在组件中注册。最后还有像 transition 这样的内置组件,是 vue 自己提供的。

在 vue 中,使用什么东西来让组件变成为全局组件呢?这是组件的一种声明方式,使用 app.component('router-link', RouterLink)

当我们把 app.use(router) 注释掉后,发现没有了 router-link这个组件了,但是却还是可以看得到 router-link 中的 Home 以及 About 。这又是为什么呢?

当一个组件没有引入,不被支持的时候, dom 会把它当成一般标签来解析。

所以我们要搞明白 .use 到底做了什么?

vue 只负责 组件思想, mvvm 响应式 等核心,其他的交给生态系统,一起开源。vue-router 是vue 生态系统中的路由模块, vue 和它生态的对接,就是这个use方法

手写 router

javascript 复制代码
import { createRouter } from './grouter/index'

现在我们就自己来写 router ,理解 router 。将原来的引入改为 grouter 文件夹下的 idnex ,在这来实现 router 中的 api 。

创建 RouterLink 和 RouterView 这俩个 vue 文件。

1. RouterLink.vue

xml 复制代码
<!-- RouterLink.vue -->
<template>
    <a :href="'#' + $props.to">
        <!-- 插槽 -->
        <slot />
    </a>
</template>

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

</script>

因为 router-link 本来渲染到页面也是 a 标签,所以使用 a 元素来创建一个超链接。href 属性通过 : 简写绑定动态值,它将一个井号 #to的值进行拼接,这样创建一个动态的链接。在单页应用中,当用户点击链接时,不会触发页面刷新,而是通过 JavaScript 更改 URL 并显示新的内容。

在子组件模板中,<slot> 标签表示了一个占位符,任何在子组件标签内部定义的内容都将被渲染到这个占位符的位置。这使得父组件可以根据需要自定义链接的显示内容,而无需修改子组件的代码。

2. RouterView.vue

xml 复制代码
<!-- RouterView.vue -->
<template>
     <component :is="component"></component>
</template>

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

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

// router-view 动态组件 展示 依赖于 url 的变化
const component = computed(() => {
   const route = router.routes.find(
    (route) => route.path == router.current.value
   )
    return router? route.component : null

})

</script>

使用 <component> 标签,这是一个特殊的 Vue 标签,允许我们根据传入的 is 属性动态地渲染不同的组件。is 属性会返回当前应该渲染的组件。计算属性根据当前 URL 路径来决定渲染哪个组件。通过查找与当前 URL 路径匹配的路由配置,返回找到的路由配置中指定的组件。

RouterView.vue 负责根据 URL 渲染正确的页面。<a> 链接组件提供了一种简单的方式来创建导航链接。结合这两个组件,我们就可以构建一个基本的手写路由系统,它允许用户通过点击链接来导航到不同的页面,并且页面会根据 URL 路径的变化动态更新。

3. index.js

javascript 复制代码
<!-- index.js -->
import RouterLink from './RouterLink.vue'
import RouterView from './RouterView.vue'
import { ref, inject } from 'vue'


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

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

// 标记一下,router 要向全局暴露
const ROUTER_KEY = '__router__'

// use 开头的是一派  hooks  函数式编程
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)
    }

}

createWebHashHistory 函数创建一个哈希历史模式的路由历史管理器,它负责监听浏览器的 hashchange 事件并获取当前 URL 的哈希值。

ROUTER_KEY 是一个符号,用于在 Vue 应用程序上下文中标识路由器实例。这在 Vue 组件之间共享路由器实例,以便各个组件可以访问到相同的路由信息和相关的方法。确保整个应用中的所有组件都可以访问同一个路由器实例,而不需要在每个组件中显式传递路由器。

useRouter 函数利用 inject 函数从 Vue 组件的上下文中获取路由器实例。

Router 类是一个构造函数,用于创建路由管理器实例。constructor 方法接收 historyroutes 作为参数,并初始化路由状态。install 方法用于将路由器实例注入到 Vue 应用程序中,并注册 RouterLinkRouterView 组件。

思路巩固

讲了这么些,最后总的来看看 vue-router 到底做了些什么事情。

1. 创建路由组件

RouterLink 负责渲染带有特定 href<a> 标签,其中 href 包含当前路由路径。用户点击时,会改变浏览器 URL 的 hash 部分,触发页面内的导航。

RouterView 负责根据当前 URL 路径动态渲染与之对应的组件。它通过计算属性确定展示哪个组件。

2. 设置路由逻辑

createWebHashHistory 创建一个简单的哈希历史管理器,用于监听 hashchange 事件,并获取当前 URL 的哈希部分作为路由路径。

Router 类 负责管理路由状态,包括当前路径、注册的路由规则等。它还包含一个 install 方法,用于将路由器实例注入到 Vue 应用程序中,并注册全局组件 RouterLinkRouterView

3. 集成到 Vue 应用

使用 createRouter 工厂函数创建路由器实例,并通过 app.use 方法安装到 Vue 应用中。这一步会将路由器实例注册到 Vue 的上下文中,并注册全局组件。

总结

我们首先回顾了一些关于 Vue Router 的基础知识,例如初始化配置、路由守卫、路由懒加载、router-linkrouter-view 的使用等。接着详细介绍了如何手动实现一个简化版的 Vue 路由器。手写一个简易版的 Vue Router 不仅有助于深入理解 Vue Router 的设计原理,还能加深对 Vue 框架的理解。 看完希望对你有帮助,一起加油。

相关推荐
用户693717500138422 分钟前
AI Agent 里的 Loop 到底是什么?
android·前端·后端
Rain的Java大神之路29 分钟前
高并发下的抢优惠券如何设计
后端
钟智强33 分钟前
AWS CloudGoat 实战:一个 SSRF 如何撬动整个云账户
后端
Ai拆代码的曹操34 分钟前
@Transactional 写在 private 方法上,事务根本没生效
后端
云技纵横38 分钟前
@Async 默认执行器又炸了:SimpleAsyncTaskExecutor 为什么不是线程池?
后端·面试
程序员Agions39 分钟前
Fypro 新手快速上手与实战指南
后端
舒心的云朵43 分钟前
用三张图片详解Asp.Net 全生命周期
后端·asp.net
卷无止境1 小时前
C++ 类型转换变迁之路:从隐式转换到 static_cast
c++·后端
孝顺的书包1 小时前
用Asp.net写自己的服务框架
后端·asp.net
糊涂的世界1 小时前
IE10、IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题
后端·asp.net