【Vue3 第二十七章】路由和状态管理

一、路由

1.1 服务端路由 与 客户端路由

  • 服务端路由
    服务端路由指的是服务器根据用户访问的 URL 路径返回不同的响应结果。当我们在一个传统的服务端渲染的 web 应用中点击一个链接时,浏览器会从服务端获得全新的 HTML,然后重新加载整个页面。
  • 客户端路由
    客户端路由和服务端路由类似,只不过它是在浏览器中运行,使用 JavaScript 处理逻辑,并利用一些基于 JS 的模板引擎或其它方式呈现页面。客户端路由通常用于单页面应用程序中,这时服务器端代码主要用于为客户端代码提供通过 ajax 技术请求的 API 接口数据。
    在单页面应用中,客户端的 JavaScript 可以拦截页面的跳转请求,动态获取新的数据,然后在无需重新加载的情况下更新当前页面。这样通常可以带来更顺滑的用户体验,尤其是在更偏向“应用”的场景下(这类场景下用户通常会在很长的一段时间中做出多次交互)。
    客户端路由可以通过 History API 或者 hashchange 事件 来管理应用当前应该渲染的视图。

1.2 实现一个简单的路由

如果你只需要一个简单的页面路由,而不想为此引入一整个路由库,你可以通过动态组件的方式,监听浏览器 hashchange 事件或使用 History API 来更新当前组件。
如下图,通过点击的方式,达到路由切换的目的:
在这里插入图片描述
主要代码如下:

<script setup>
import {
    
     ref, computed } from 'vue'
import A from './A.vue'
import B from './B.vue'
import NotFound from "./NotFound.vue"

const routes = {
    
    
    '/': A,
    '/b': B
}

const currentPath = ref(window.location.hash)
window.addEventListener('hashchange', () => {
    
    
    currentPath.value = window.location.hash
})
const currentView = computed(() => {
    
    
    return routes[currentPath.value.slice(1) || '/'] || NotFound
})
</script>
<template>
    <div>
        <div>
            <a href="#/">A</a>
            <a href="#/b" style="margin-left: 20px">B</a>
        </div>
        <br>
        <Transition name="fade">
            <component :is="currentView" style="margin-top:50px" tag="div"></component>
        </Transition>
    </div>
</template>
<style scoped lang="less">
.fade-enter-from {
    
    
    opacity: 0;
}

.fade-enter-active {
    
    
    transition: opacity 1s 0.5s ease;
}https://code.7-plan.com/web/operation-management

.fade-leave-to {
    
    
    opacity: 0;
}

.fade-leave-active {
    
    
    transition: opacity .5s ease;
}
</style>

1.3 官方路由库 - Vue Router

Vue Router - 为 Vue.js 提供富有表现力、可配置的、方便的路由
在这里插入图片描述
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。功能包括:

  • 嵌套路由映射
  • 动态路由选择
  • 模块化、基于组件的路由配置
  • 路由参数、查询、通配符
  • 展示由 Vue.js 的过渡系统提供的过渡效果
  • 细致的导航控制
  • 自动激活 CSS 类的链接
  • HTML5 history 模式或 hash 模式
  • 可定制的滚动行为
  • URL 的正确编码

关于项目路由的详细配置和使用,详见官方文档

数字化管理平台
Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus
Vue权限系统案例
个人博客地址

二、状态管理

2.1 在 Vue 中,每一个组件实例都是一个独立的单元,包含三个部分:

  • 状态
    驱动整个应用的数据源

  • 视图
    对状态的一种声明式映射

  • 交互
    状态根据用户在视图中的输入而做出响应变更的可能方式
    在这里插入图片描述
    当多个组件共享一个共同状态时,可以利用 Vue 提供的 API,在抽取的公共组件上做状态管理:

  • props 属性传递(深层次组件嵌套,会造成 prop 逐级透传问题,会显得非常麻烦)
    在这里插入图片描述

  • provide/inject 穿透(可以解决深层次数据传递问题)
    在这里插入图片描述

  • event 自定义事件

  • ref 引用获取父/子实例

  • globalProperties 定义全局状态

  • eventBus 公交总线

2.2 通过 Vue 响应式 API 实现一个简单的状态管理
创建一个共享组件,并使用 reactive 创建一个响应式状态对象

// store.js
import {
    
     reactive } from 'vue'

export const store = reactive({
    
    
  count: 0
})

在需要这个状态的组件中分别引入并使用

<!-- ComponentA.vue -->
<script setup>
import {
    
     store } from './store.js'
</script>

<template>From A: {
    
    {
    
     store.count }}</template>
<!-- ComponentB.vue -->
<script setup>
import {
    
     store } from './store.js'
</script>

<template>From B: {
    
    {
    
     store.count }}</template>

在这两个组件中,尝试去修改 store 对象,看一下视图是否会自动更新

<template>
  <button @click="store.count++">
    From B: {
    
    {
    
     store.count }}
  </button>
</template>

刷新页面,发现点击操作后,两个引用的组件中,这个状态都同步更新了。
然而,我们学习JS高级或者设计模式的时候,再三强调不建议这么做!为什么,想一想,随意一个组件都可以轻易的去修改状态,这符合代码的健壮性和可维护性原则吗?
所以为了确保状态改变的逻辑像状态本身一样集中,建议在 store 上,通过方法的方式来表达修改状态的意图,提供对应的接口去进行响应的操作,而不是随意修改。

共享组件代码增加操作接口函数如下

// store.js
import {
    
     reactive } from 'vue'

export const store = reactive({
    
    
  count: 0,
  increment() {
    
    
    this.count++
  }
})

其它组件中通过对应的接口,完成状态的处理操作

<template>
  <button @click="store.increment()">
    From B: {
    
    {
    
     store.count }}
  </button>
</template>

请注意这里点击的处理函数使用了 store.increment(),带上了圆括号作为内联表达式调用,因为它并不是组件的方法,并且必须要以正确的 this 上下文来调用。

2.3 通过上面不难看出,Vue 组件本身其实已经实现了对响应式状态的管理。那既然这样,为什么我们还要使用 Pinia 或 Vuex 这些状态管理器呢?
这是因为在大规模的生产应用中,还有很多其它事项要考虑:

  • 更强的团队协作约定
  • 与 Vue DevTools 集成,包括时间轴、组件内部审查和时间旅行调试
  • 模块热更新 (HMR)
  • 服务端渲染支持

下面来展开讲一讲状态管理的应用

Pinia - 符合直觉的 Vue.js 状态管理库。类型安全、可扩展性以及模块化设计。甚至让你忘记正在使用的是一个状态库。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39335404/article/details/131181497