1. 状态管理
在程序开发过程中,有很多页面需要共享一些数据,这些数据需要我们保存在程序的某一个地方。管理这些数据的过程就叫做状态管理。
2. Pinia
Pinia 是一个专为 Vue 设计的状态管理工具,它比 Vuex 学起来更简单,而且同时支持 Vue2 和 Vue3 语法。
中文官网:
css
https://pinia.web3doc.top/

3. 安装配置
命令行输入:
css
npm install pinia
在 main.js 文件中配置 Pinia
css
import { createApp } from 'vue'
import App from './App.vue'
const pinia = createPinia()
app.use(pinia).mount("#app")
4. 创建 Store
Pinia 中的 Store 主要包含三部分:state、getters、actions,创建方式同时支持 Vue2 和 Vue3 语法。
- Vue2 选项式API

- Vue3 组合式API

这里我个人更推荐使用选项式 API,因为更直观。
4.1 id
在 Pinia 中,每一个 Store 都要有唯一的名称,或者唯一的id。
命名 id 的方式有 2 种:
第1种:将 id 作为 defineStore 方法的参数

第2种:在 defineStore 方法体内定义 id

4.2 State
State 其实就是我们需要存储的数据
css
state: () => ({
count: 1,
name:"知否君",
menuList:[]
}),
4.3 Getter
Getter 是计算过后的数据
css
getters: {
doubleCount() {
return this.count * 2;
},
},
4.4 Action
Action 就是操作数据的一些方法
css
actions: {
// 自增操作
increment() {
this.count++;
},
},
在 Pinia中,如果要处理异步请求,我们需要采用 async-await 的方式:
css
actions: {
// 获取菜单列表
async getMenuList() {
const { data } = await axios.get('/api/menuList')
this.menuList = data
}
},
5. Pinia 案例
5.1 案例一:计数
1.新建 counter.js

2.导入 counter
css
import { useCounterStore } from "@/store/counter";
const useCounter = useCounterStore();
3.state 和方法
css
<template>
<el-card style="margin: 20px">
<template #header>
<span style="font-weight: bold">新一代Vue存储库Pinia</span>
</template>
<!-- 计数操作 -->
<p>数值:{{ useCounter.count }}</p>
<p>2倍数值:{{ useCounter.doubleCount }}</p>
<el-button type="primary" @click="useCounter.increment">点击+1</el-button>
<el-button type="primary" @click="useCounter.$reset()">重置</el-button>
</el-card>
</template>
4.完整代码
css
<template>
<el-card style="margin: 20px">
<template #header>
<span style="font-weight: bold">新一代Vue存储库Pinia</span>
</template>
<!-- 计数操作 -->
<p>数值:{{ useCounter.count }}</p>
<p>2倍数值:{{ useCounter.doubleCount }}</p>
<el-button type="primary" @click="useCounter.increment">点击+1</el-button>
<el-button type="primary" @click="useCounter.$reset()">重置</el-button>
</el-card>
</template>
<script setup>
import { useCounterStore } from "@/store/counter";
const useCounter = useCounterStore();
</script>
注:useCounter.$reset() 方法可以重置 Pinia 中的数值,但是前提 store 语法必须是 Vue2 选项式 API ,不然会失效。
5.效果

6.解构
注: 直接从 store 中解构的数据不能实时响应,要想保持实时响应,必须用 storeToRefs() 方法包裹。
css
<template>
<el-card style="margin: 20px">
<template #header>
<span style="font-weight: bold">新一代Vue存储库Pinia</span>
</template>
<!-- 计数操作 -->
<p>数值:{{ count }}</p>
<p>2倍数值:{{ doubleCount }}</p>
<el-button type="primary" @click="useCounter.increment">点击+1</el-button>
<el-button type="primary" @click="useCounter.$reset()">重置</el-button>
</el-card>
</template>
<script setup>
import { useCounterStore } from "@/store/counter";
import { storeToRefs } from "pinia";
const useCounter = useCounterStore();
const { count, doubleCount } = storeToRefs(useCounter);
</script>
5.2 案例二:添加用户
1.新建 user.js

2.获取 state 和调用方法
css
<template>
<el-card style="margin: 20px">
<template #header>
<span style="font-weight: bold">新一代Vue存储库Pinia</span>
</template>
<!-- 添加用户 -->
<el-divider>添加用户</el-divider>
<el-form ref="userFormRef" :model="userForm" label-width="120px" style="width: 40%">
<el-form-item label="姓名:" prop="name">
<el-input v-model="userForm.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="年龄:" prop="age">
<el-input-number
style="width: 100%"
:min="18"
controls-position="right"
v-model="userForm.age"
/>
</el-form-item>
<el-form-item label="学校:" prop="school">
<el-input v-model="userForm.school" placeholder="请输入学校" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="useUser.addUser(userForm)">添加</el-button>
<el-button @click="useUser.$reset()">重置Pinia数据</el-button>
<el-button @click="useUser.deleteUser">删除所有</el-button>
</el-form-item>
</el-form>
<!-- 用户列表 -->
<el-divider>用户列表</el-divider>
<div v-if="userList.length > 0">
<el-tag style="margin: 0px 10px" v-for="users in userList"
>{{ users.name }}:{{ users.age }}:{{ users.school }}</el-tag
>
</div>
</el-card>
</template>
<script setup>
import { useUserStore } from "@/store/user";
import { reactive, ref } from "vue";
import { storeToRefs } from "pinia";
const useUser = useUserStore();
const { userList } = storeToRefs(useUser);
// userForm
const userForm = reactive({ name: "", age: "", school: "" });
</script>
3.效果

6. 持久化

在使用 Pinia 的时,我们会发现刷新页面之后,数据又重置了,这时候我们可以使用 Pinia 的 Persist 插件将数据持久化到本地。
6.1 安装 pinia-plugin-persist 插件
css
npm install pinia-plugin-persist
6.2 在 main.js 配置 pinia-plugin-persist
css
import App from './App.vue'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersist)
app.use(pinia)
app.mount("#app")
6.3 使用持久化插件
在 store 添加
css
// 开启持久化
persist: { enabled: true }

我们发现该插件默认是将数据存储到 sessionStorage 中,key 值默认是 store 的 id 值,value 默认存储该 Store 的所有 state。

我们还可以自定义存储的 key 、持久化引擎和要持久化哪些数据:

