理解 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 框架的理解。 看完希望对你有帮助,一起加油。

相关推荐
刚刚好ā25 分钟前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
qq_17448285751 小时前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦1 小时前
Scala的Array(2)
开发语言·后端·scala
2401_882727572 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
心仪悦悦2 小时前
Scala中的集合复习(1)
开发语言·后端·scala
会发光的猪。3 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客3 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
代码小鑫3 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖3 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring