文章目录
1.前言
由于在日常开发中会有一部分前端的开发任务,会涉及到Vue的项目的搭建、迭代、构建发布等操作,所以想系统的学习一下Vue相关的知识点,本专题会依照Vue的搭建、开发基础实践、进阶用法、打包部署的顺序进行记录,同时也会提到一些功能在实际生产环境中的使用。
历史文章链接如下:
《Vue3搭建、路由配置与基本语法》
《响应式变量、双向绑定、计算属性、监听器》
《优雅使用VUE3 组件特性:组件定义、组件注册、事件监听、双向绑定》
《优雅使用VUE3 组件特性:属性透传、依赖注入、组件插槽、动态组件》
《生命周期函数、组合式函数的使用》
《Vue3使用vite处理环境变量、打包部署、nginx配置》
最近在公司开发的时候得到这么一个需求,需要给一个旧的系统加上一些按钮权限,考虑了插件、透传、依赖注入等方式来实现,但是都有一定的局限性,最终采用了Vuex全局状态管理的方式来实现了这个需求。
本篇会讲解一下Vue中状态的概念,以及全局状态组件 Vuex
和 Pinia
的使用,这里之所以会使用Vuex,是因为这个旧的项目是通过Vue2进行编写的,如果是Vue3项目的话,推荐使用Pinia,比Vuex更轻量、更简洁、功能更加强大。
2.状态的概念
在学习这两个组件之前,我们先了解一下什么是状态。
其实,只要使用过Vue的响应式变量,就已经使用过状态了,我们将Vue的组件可以分成3个部分,分别是:状态、视图、交互
- 状态:所谓的状态,就是在Vue组件中的数据部分,用于驱动应用的数据源。
- 视图:对状态的映射,也就是通过数据渲染出的DOM元素。
- 交互:监控了视图中的数据输入动作,将视图中输入的值传递给数据源。
他们3者可以形成一个单项的数据流,即:状态的变更会触发视图的变化,用户在视图上输入也会通过交互传递给状态。
上面所说的状态,基本上局限与某个特定的组件中,而我们在实际的开发中可能会有这样的一种需求:提供一个数据源,让所有组件都可以使用,我们可以简单的把这样的一种数据源叫做全局状态,可以使用Vuex或Pinia来实现。
之所以不用组件的逐级透传和依赖注入的方式,是因为有时候组件并不完全在同一个组件树上。我们针对不同的业务功能模块,可能会有不同的组件树根节点,如下图所示:
在这样的模块划分下,不管是透传还是依赖注入,都需要在各自的根节点上定义一次“全局状态”,供子节点使用,这样依然会有重复的代码。
3.Vuex管理状态
接下来就通过实现上述需求的方式,来讲解Vuex的简单使用,更详细的使用方式可以参考《Vuex文档》。
先根据需求拆解一下需要完成的任务:
- 需要通过一个全局状态,让所有组件可以直接使用。
- 需要提供一个
setter
方法,修改这个全局状态的值。 - 由于权限列表是来自于后端服务,所以需要有一个异步请求操作。
综上,会使用到Vuex中的 State
,Mutation
,Action
三种特性,其中 State 就是提供给各个组件使用的全局特性,Mutation 则是 Stage 的修改入口,Action 是异步操作,用于异步提交 Mutation。
此外,可以利用插件系统将定义好的功能注入到各个组件中,让组件可以直接使用。
3.1.Vuex安装及功能定义
因为我这里是一个Vue2的旧版本代码库,不支持Vuex4以上的版本,所以选择了一个3.x的版本,通过npm安装。
npm install vuex --save @3.6.2
安装完成之后,在src
根目录下创建一个store
目录,并创建index.js
文件,内容如下:
import Vuex from 'vuex'
import Vue from "vue";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
// 权限全局状态
authMap: {}
},
mutations: {
// 定义更新权限的setter方法
setAuthMap(state, authMap) {
state.authMap = authMap;
}
},
actions: {
// 定义一个异步请求方法,用于获取权限
batchAuth(context) {
// 此处是模拟数据,实际开发中替换了axios发起请求
let data = {
"user:list": true,
"user:add": false
}
context.commit('setAuthMap', data);
}
}
})
// 导出组件
export default store
3.2.全局注入及使用
想要任意组件都可以直接使用上面定义好的store
,则需要在main.js
中通过插件机制进行注入:
import Vue from "vue";
import App from "./App.vue";
import store from "./store"; // 引入 store 文件
new Vue({
store, // 注册 store
render: h => h(App),
}).$mount("#app");
注册完成之后,就可以通过this.$stroe
使用了。
由于权限列表并不会经常变化,所以我们只需在进入系统时查询一次即可,即:在App.vue
的生命周期钩子中执行,通过 dispatch
调用action中定义的异步方法。
mounted() {
this.$store.dispatch('batchAuth');
}
然后在对应组件的按钮上,也可以直接使用store
,例如:
<el-button type="primary" @click="openDialog()"
v-if="$store.state.authMap['user:add']">新增用户
</el-button>
此时由于user:add
为false,这里的新增用户按钮就会对当前的使用者隐藏。其他的使用方式也是类似的,我们可以从authMap
通过某个固定的key取出一个布尔值,则可以*的处理DOM的状态,例如:v-show
,:disabled
等等。
4.Pinia管理状态
如果是一个新的Vue3项目,使用Pinia来管理状态是一个更佳的选择,配合组合式API使用非常简洁易用。
4.1.Pinia中的核心概念
Pinia中有4个核心的概念,分别是:store
, state
, getter
, action
。
-
store
:用于来承载全局状态的实体,它不会挂接在某个组件树上,而是每个组件都可以直接引入并使用它。 -
state
:是应用程序的状态数据,我们可以上面定义自己需要的任何数据,例如用户信息、页面状态、列表数据等。state
在组件式API中类似于data()
,在组合式API中类似于ref
。 -
getter
:用于获取state中数据的函数,并做二次计算,可用于计算衍生数据、过滤数据等场景。getter
与computed
操作类似。 -
action
:是store
中的函数,多用于修改state
的值,它类似于method
的作用。
4.2.Pinia的定义与使用
安装并配置pinia
:
npm install pinia
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
// 全局组件引入
app.use(pinia)
// 挂载应用
app.mount('#app')
接下来是创建store
,类似于Vuex的做法,我们可以./store
目录下创建一个useAuthMapStore.js
文件,通过defineStore
创建一个store对象,对象名遵循以use
开头,以store
结尾的规则,第一个参数是当前对象的id,需要保证唯一,第二个参数就是选项式API中的选项 option。
综上,上面的Vuex 定义的authMap,用Pinia来编写就简洁多了。
import { defineStore } from "pinia";
export const useAuthMapStore = defineStore("authMap", {
state: () => ({ authMap: {} }),
actions: {
// async 异步调用
async batchAuth() {
this.authMap = {
"user:list": true,
"user:add": false
};
}
}
});
在APP.vue中触发batchAuth
方法:
<script setup>
import { useAuthMapStore } from "@/store/module/useAuthMapStore";
useAuthMapStore().batchAuth();
</script>
在任意组件中使用:
<template>
<div class="hello">
<div> {{ store.authMap }}</div>
</div>
</template>
<script setup>
import { useAuthMapStore } from "../store/module/useAuthMapStore";
const store = useAuthMapStore();
</script>
4.3.使用组合式API定义Store
如果是使用组合式API,也可以这么写:
import { defineStore } from "pinia";
import { ref } from "vue";
export const useAuthMapStore = defineStore("authMap", () => {
const authMap = ref({});
function batchAuth() {
authMap.value = {
"user:list": true,
"user:add": false
};
}
return { authMap, batchAuth };
});
使用的方式和选项式API的使用方式是一样的,个人更建议使用组合式API来定义Store,在Vue3上的支持性更好,更灵活,风格也统一。
在上述的例子中,还没有提到如何使用getter
方法,在组合式API中的getter
方法其实就是一个属性计算,通过computed
实现即可,改造后的代码如下:
export const useAuthMapStore = defineStore("authMap", () => {
const authMap = ref({});
const anotherAuthMap = computed(() => {
let value = JSON.parse(JSON.stringify(authMap.value));
value["user:view"] = true;
return ref(value);
});
function batchAuth() {
authMap.value = {
"user:list": true,
"user:add": false
};
}
return { authMap, batchAuth, anotherAuthMap };
});
然后验证一下结果:
<template>
<div class="hello">
<div> {{ store.authMap }}</div>
<div> {{ store.anotherAuthMap }}</div>
</div>
</template>
5.总结
本篇主要讲述Vue中的状态、全局状态的概念以及如何通过Vuex和Pinia来管理全局状态,其中Vuex更适合与Vue2的旧项目,而Pinia适合与使用Vue3构建的新项目,Pinia使用起来更加轻量和简洁,配合组合式API使用效果更加。
关注以下的知识点:
- Vuex:
- 核心概念:
State
,Mutation
,Action
,State用于定义数据,Mutation用于修改数据,Action是异步执行的方法,往往是用于异步获取数据后调用Mutation修改数据。 - Vuex可以通过插件进行全局注入,通过
this.$store
语法进行调用,其中this.$store.state
用于获取状态数据,this.$store.dispatch
用于异步调用Action中的函数。
- 核心概念:
- Pinia
- 核心概念:分别是:
store , state , getter , action
。-
store
:用于来承载全局状态的实体,它不会挂接在某个组件树上,而是每个组件都可以直接引入并使用它。 -
state
:是应用程序的状态数据,我们可以上面定义自己需要的任何数据,例如用户信息、页面状态、列表数据等。 -
getter
:用于获取state中数据的函数,并做二次计算,可用于计算衍生数据、过滤数据等场景。 -
action
:是store
中的函数,多用于修改state
的值。
-
- 定义:通过
defineStore
定义一个store对象,第一个参数为对象id,第二个参数则是定时对象体。 - 命名:通常以
use
开头,以store
结尾,建议文件名与store对象名保持一致,例如:useCounterStore
和useCounterStore.js
。
- 核心概念:分别是: