什么是Pinia?
Pinia是新一代的轻量级状态管理库,它允许跨组件或页面共享状态,解决了多组件间的数据通信,使数据操作更加简洁。
Pinia与Vuex相比的主要优点
Pinia支持Vue 2和Vue 3,支持选项式API和组合式API写法。
Pinia简化了状态管理库的使用方法,抛弃了mutations,只有state、getters和actions,让代码编写更容易也更直观。
Pinia不需要嵌套模板,符合Vue 3中的组合式API,让代码更加扁平化。
Pinia提供了完整的TypeScript支持。
Pinia分模块不需要借助modules,使代码更加简洁,可以实现良好的代码自动分隔。
Pinia支持Devtools调试工具,便于进行调试。
Pinia体积更小,性能更好。
Pinia支持在某个组件中直接修改Pinia的state中的数据。
Pinia支持服务端器渲染。
使用npm或yarn包管理工具安装Pinia。
# 使用yarn包管理器安装
yarn add pinia@2.0.27 --save
# 使用npm包管理器安装
npm install pinia --save
Pinia安装完成后,如何使用呢?
在项目中使用Pinia时,通常先在项目中创建一个store模块,然后创建并挂载Pinia实例。其中,store模块是用于管理状态数据的仓库。
① 编写store模块,创建src\store\index.js文件。
import { defineStore } from 'pinia'//导入defineStore()函数
export const useStore = defineStore('storeId', {//状态管理容器的名称
state: () => {},//管理
getters: {},//再次编译,得到新的数据
actions: {}//定义事件处理方法
})
② 在src\main.js文件中创建并挂载Pinia实例。
import { createApp } from 'vue'
import './style.css'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia() // 创建Pinia实例
app.use(pinia) // 导入Pinia实例
app.mount('#app')
要求使用Pinia实现计数器案例:
计数器初始页面定义了2个初始数字0和100,定义了“+”和“-”2个按钮。每次单击“+”按钮,数字从0自增1;每次单击“-”按钮,数字会从100自减1。
计数器初始页面效果如下图所示。

在计数器初始页面中单击“+”按钮,其后数字从0变为1,效果如下图所示。

在计数器初始页面中单击“-”按钮,其后数字从100变为99,效果如下图所示。

讲解计数器案例的实现
清空src\App.vue文件中的内容,重新编写如下代码。
<template>
<p>
每次增加1:<button @click="increment">+</button>
数字:0
</p>
<p>
每次减少1:<button @click="reduction">-</button>
数字:100
</p>
</template>
<script setup>
const increment = () => { }
const reduction = () => { }
</script>
<style>
button {
background-color: aquamarine;
}
</style>
创建src\store\index.js文件。
import { defineStore } from 'pinia'
export const useStore = defineStore('storeId', {
state: () => {
return {
add: 0,
reduce: 100
}
},
getters: {},
actions: {
increase() {
this.add++
},
decrease() {
this.reduce--
}
}
})
修改src\App.vue文件,调用actions中定义的increase()方法和decrease()方法。
<script setup>
import { useStore } from './store'
import { storeToRefs } from 'pinia'
const store = useStore()
const { add, reduce } = storeToRefs(store)
const increment = () => {
store.increase()
}
const reduction = () => {
store.decrease()
}
</script>
在<template>模板中输出state中的数据,显示在页面中。
<p>
每次增加1:<button @click="increment">+</button>
数字:{{ add }}
</p>
<p>
每次减少1:<button @click="reduction">-</button>
数字:{{ reduce }}
</p>
Pinia模块化应用场景?
在复杂的大型项目中,如果将多个模块的数据都定义到一个store对象中,那么store对象将变得非常大且难以管理,此时,可以使用Pinia直接定义多个模块,Pinia不需要像Vuex一样使用modules模块,它可以在src\store目录中直接定义对应模块,一个.js文件为一个模块。

讲解user.js和shop.js模块的创建
在src\store目录下,新建user.js和shop.js文件作为两个模块,其中,user.js文件用于保存用户信息数据,shop.js文件用于保存商品信息数据。
创建src\store\user.js文件,编写用户信息数据。
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => {
return {
name: '小明',
sex: '男',
age: 18
}
},
getters: {},
actions: {}
})
创建src\store\shop.js文件,编写商品信息数据。
import { defineStore } from 'pinia'
export const useShopStore = defineStore('shop', {
state: () => {
return {
list: [
{
id: '01',
name: '手机',
price: 2000
},
{
id: '02',
name: '音响',
price: 5000
}
]
}
},
getters: {},
actions: {
increase() {
this.add++
},
decrease() {
this.reduce--
}
}
})
创建src\components\User.vue文件,在页面中显示用户信息数据。
<template>
<div>user模块:
<p>姓名:{{ name }}</p>
<p>性别:{{ sex }}</p>
<p>年龄:{{ age }}</p>
</div>
</template>
<script setup>
import { useUserStore } from '../store/user.js'
import { storeToRefs } from 'pinia'
const user = useUserStore()
const { name, sex, age } = storeToRefs(user)
</script>
创建src\components\Shop.vue文件,在页面中显示商品信息数据。
<template>
shop模块:
<div v-for="item in list">
<p>商品id:{{ item.id }}</p>
<p>商品名称:{{ item.name }}</p>
<p>商品价格:{{ item.price }}元</p>
</div>
</template>
<script setup>
import { useShopStore } from '../store/shop.js'
import { storeToRefs } from 'pinia'
const shop = useShopStore()
const { list } = storeToRefs(shop)
</script>
在项目开发中,使用Pinia进行状态管理时,若想要刷新浏览器后,仍保留之前的操作状态,可以通过Pinia的持久化插件pinia-plugin-persist实现。
安装pinia-plugin-persist
使用npm或yarn包管理工具安装pinia-plugin-persist
# 使用npm包管理工具安装
npm install pinia-plugin-persist --save
# 使用yarn包管理工具安装
yarn add pinia-plugin-persist --save
在src\main.js文件中导入并挂载pinia-plugin-persist插件。
import { createApp } from 'vue'
import './style.css'
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
import App from './components/Shop.vue'
const pinia = createPinia()
pinia.use(piniaPluginPersist)
const app = createApp(App)
app.use(pinia)
app.mount('#app')
挂载pinia-plugin-persist插件后,在模块中实现持久化存储的示例代码如下。
persist: {
enabled: true, // 开启数据缓存
strategies: [
{
key: 'StoreId1', // 当前store的id
storage: localStorage, // 存储方式
paths: ['字段'] // 指定要持久化的字段
}
]
}
1. 全部数据持久化存储
下面以my-pinia项目为例,演示如何使用Pinia实现全部数据持久化存储。当用户单击“增加年龄”按钮时,年龄值将会改变,此时关闭浏览器或刷新页面后,要求页面显示最新修改的年龄值。
(1)在src\components\User.vue文件中定义“增加年龄”按钮。
<template>
<div>user模块:
<p>姓名:{{ name }}</p>
<p>性别:{{ sex }}</p>
<p>年龄:{{ age }}</p>
<button @click="changeAge">增加年龄</button>
</div>
</template>
(2)修改src\store\user.js文件,在actions中定义一个改变年龄的方法,并实现持久化存储。
actions: {
changeAge() {
this.age++
},
},
persist: {
enabled: true,
strategies: [
{
key: 'user',
storage: localStorage
}
]
}
(3)在src\components\User.vue文件中定义changeAge()方法,在该方法中调用actions中定义的changeAge()方法。
const changeAge = () => {
user.changeAge()
}
全部数据持久化存储的初始页面效果、单击2次“增加年龄”按钮后的页面效果如下图所示。

注意:
单击2次“增加年龄”按钮后,会发现年龄值变为了20,此时刷新页面后,年龄值仍为20,表明已实现数据的持久化存储。
2. 部分数据持久化存储
下面以my-pinia项目为例,演示如何使用Pinia实现部分数据持久化存储。在页面中新增一个“改变姓名”按钮,当用户单击“增加年龄”按钮时,年龄值将会改变;当用户单击“改变姓名”按钮时,姓名值将会改变。当关闭浏览器或刷新页面后,要求页面显示最新修改的年龄值,而不保存最新修改的姓名值。
(1)修改src\store\user.js文件,在actions中定义一个改变姓名的方法。
changeName() {
this.name = '小亮'
}
(2)修改src\store\user.js文件中持久化存储的代码,通过paths指定要持久化存储的字段。
persist: {
enabled: true,
strategies: [
{
key: 'user',
storage: localStorage,
paths: ['age']
}
],
}
(3)在src\components\User.vue文件中找到“增加年龄”按钮,在该按钮下方增加一个“改变姓名”按钮。
<button @click="changeName">改变姓名</button>
(4)修改src\components\User.vue文件,定义changeName()方法,在该方法中调用actions中定义的changeName()方法。
const changeName = () => {
user.changeName()
}
打开开发者工具,在控制台面板中执行localStorage.clear()清除localStorage数据,清除后关闭开发者工具并刷新页面,部分数据持久化存储的初始页面效果如下图所示。

单击“增加年龄”按钮,年龄从18变为19;单击“改变姓名”按钮,姓名会从“小明”变为“小亮”,年龄改变的效果、姓名改变的效果如下图所示。

刷新页面后的页面效果如下图所示。

注意:
页面中显示的年龄为19,姓名为小明,说明成功实现了年龄数据的持久化存储效果。