前言
什么是pinia?
pinia是一个用于Vue.js应用的状态管理库,主要作用是在Vue应用的不同组件间共享和管理状态。相当于一个大型的仓库,组件想要什么都能去仓库取。
如果我想实现两个组件的内容都在App.vue上展示,实现兄弟通讯的效果。
- 首先我们创建一个vue项目
- 创建以下文件
App.vue
add.vue和count.vue的父组件
vue
<template>
<Add />
<Count />
</template>
<script setup>
import Add from './components/add.vue'
import Count from './components/count.vue'
</script>
<style lang="css" scoped>
</style>
add.vue
定义一个add按钮,当点击按钮时,num会进行累加。
vue
<template>
<button @click="num++">add</button>
</template>
<script setup>
import {num} from '@/global.js'
</script>
<style lang="css" scoped>
</style>
count.vue
将num从global.js引入进来
vue
<template>
<div>
<h2>{{ num }}</h2>
</div>
</template>
<script setup>
import {num} from '@/global.js'
</script>
<style lang="css" scoped>
</style>
global.js
定义一个全局变量num并将其抛出,其为响应式变量,当点击add按钮时,num的值会发生变化并且在页面上实时更新。
js
import {ref} from 'vue'
export const num = ref(0)
pinia
- 首先在项目中安装pinia,指令:
npm i pinia
。
- 安装成功后,在src文件夹下创建一个文件夹store,再到store文件夹下创建一个index.js文件。
- 在index.js文件下引入createPinia函数,用于创建一个pinia实例,再调用createPinia函数来创建一个新的pinia实例,这个实例就是状态管理仓库,再使用
export default
将该仓库抛出。 - 导入
pinia-plugin-persist
插件添加到store实例中,状态数据会被保存在浏览器的localStorage
中。
js
import {createPinia} from 'pinia';
import piniaPluginPersist from 'pinia-plugin-persist';
const store = createPinia();
store.use(piniaPluginPersist);
export default store;
- 要让该仓库在全局生效,就将该仓库引入到
main.js
当中。
js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
- 在store文件夹下创建一个user.js,从pinia模块导入defineStore函数,其作用是创建Pinia store实例,接受一个配置对象作为参数,这个对象包含了store的名字、state、getters、actions、persist等属性。
- 定义store的id为user,state为仓库的数据源,返回一个userInfo对象,里面包含用户的基本信息,如name、sex、money。
- actions是方法集合,用于改变store的状态,里面定义了
changeUserName
、changeUserSex
、changeUserMoney
三个方法用于修改用户的信息。 - getters是仓库中的计算属性,
afterMoney
返回用户资金加上额外的10000元的结果。 - persist用于开启数据持久化,即当页面关闭或浏览器重启时,store中的某些状态会被保存到本地存储(localStorage),再次刷新页面数据不会回到初始状态,paths指定哪些状态需要持久化。
- 要实现持久化存储还需要装一个插件,在终端输入该指令:
npm i pinia-plugin-persist
。
js
import { defineStore } from 'pinia'; // defineStore 是store 的一部分
export const useUserStore = defineStore({
id: 'user',
state: () => { // 仓库里的数据源
return{
userInfo: {
name: 'lt',
sex: '男',
age: 18
}
}
},
actions: { // 专门用来修改state
changeUserName(name) {
this.userInfo.name = name; // 仓库的数据源应该由仓库自己修改
},
changeUserSex(sex) {
this.userInfo.sex = sex;
},
changeUserAge(n) {
this.userInfo.age += n;
}
},
getters: { // 仓库中的计算属性
afterAge(state) {
return state.userInfo.age + 10
}
},
persist: { // 开启数据持久化
enabled: true,
strategies: [
{
paths: ['userInfo'],
storage: localStorage,
}
]
}
});
User.vue
在components文件夹下创建一个User.vue
文件,并且在App.vue中将该组件引入,用于展示用户的数据。
const userStore = useUserStore()
将useUserStore的执行结果赋给userStore,即将仓库内的数据赋给了userStore。- 由于仓库是响应式的,所以
userStore.userInfo.name
是响应式数据,所以当仓库内用户的name改变时,页面上的姓名会更新。如果此处换一种写法:
vue
<template>
<li>姓名:{{ name }}</li>
</template>
<script setup>
const name = userStore.userInfo.name
</script>
这种写法在改变了仓库的name之后,页面上的姓名不会更新,因为name
不会被重新赋值。虽然userStore.userInfo.name
是响应式的,但是name
不是响应式的数据。
- 还可使用computed计算属性将age变成响应式数据,所以当age的值发生变更时,页面会更新age的值。
- 引入
storeToRefs
函数,将store中的状态转换为ref对象,由于storeToRefs(userStore)会返回一个对象,于是需要用到解构语法,获得一个名为userInfo的ref对象,就可以直接使用userInfo.sex
来访问或者更新store中的userInfo状态。 userStore.afterAge
不需要写成userStore.afterAge()
,因为getter在背后被自动执行,只需要访问其结果,而不需要显示地调用它。
vue
<template>
<ul>
<li>姓名:{{ userStore.userInfo.name }}</li>
<li>性别:{{ userInfo.sex }}</li>
<li>年龄:{{ age }}</li>
<li>十年之后年龄:{{ userStore.afterAge }}</li>
</ul>
</template>
<script setup>
import {computed} from "vue";
import {useUserStore} from "@/store/user";
import {storeToRefs} from "pinia";
const userStore = useUserStore();
const age = computed(() => userStore.userInfo.age)
const {userInfo} = storeToRefs(userStore) // storeToRefs 把整个仓库的数据源变成一个响应式对象
// console.log(userStore);
</script>
<style lang="css" scoped>
</style>
Update-user.vue
在components文件夹下再创建一个Update-user.vue
文件,里面放入一些按钮,当点击按钮时改变相应的数据。将该组件也引入App.vue
。
- 分别为这些按钮绑定点击事件,在仓库中的actions中写入一些方法,当点击按钮时则会访问userStore内的方法,通过调用这些方法来改变相应变量的值。
vue
<template>
<button @click="changeName">修改仓库中的用户姓名</button>
<button @click="changeSex">修改仓库中的用户性别</button>
<button @click="changeAge">年龄</button>
</template>
<script setup>
import {useUserStore} from '@/store/user';
const userStore = useUserStore();
const changeName = () =>{
// userStore.userInfo.name = 'ltt'; // 不要这种代码
userStore.changeUserName('ltt');
};
const changeSex = () =>{
userStore.changeUserSex('女');
};
const changeAge = (n) =>{
userStore.changeUserAge(1);
};
</script>
<style lang="css" scoped>
</style>
最终执行结果
结语
快自己动手敲一敲吧