前言
Pinia是一个专为Vue.js设计的状态管理库,特别是针对Vue 3进行了优化。它由Vue.js官方团队维护,提供了一种简单、直观且强大的方式来管理Vue.js应用程序中的状态。 今天我们将学习Pinia,并且通过使用他来实现兄弟通讯
实现兄弟通讯
在上一篇的文章中我们学习了子父组件通讯的4种方法,(希望你不会忘记,如果忘记了请及时回去复习),那么现在让我们想想,如何实现兄弟通讯?
场景
现在我给你3个组件,App.vue作为根组件,add.vue和count.vue作为兄弟组件分别需要实现递加和传入初始值的功能。怎么实现以下效果?
实操
首先可以明确的是需要在App.vue中引入两个子组件,然后实现add.vue和count.vue之间的通讯。实现他俩的通讯需要新建一个文件,将这个文件中的值抛出,然后再到这两文件中引入,有点子小麻烦。
全局文件:
csharp
// 在src下新建的文件
import { ref } from 'vue'
export const num = ref(0)
兄弟组件:
add.vue
<template>
<div>
<button @click="num++">add -- {{ num }}</button>
</div>
</template>
<script setup>
import { num } from '@/global'
</script>
兄弟组件:
count.vue
<template>
<div>
{{ num }}
</div>
</template>
<script setup>
import { num } from '@/global'
</script>
最后功能是实现了,但是怎么多少有点自欺欺人的味道呢?这时候
Pinia
在我们上面的尝试中,虽然勉强算是实现了兄弟通讯,但这种通讯方式在大型项目中的安全漏洞会非常多,在开发复杂的项目时,我们就不得不使用今天的主角------------ pinia
Pinia 是 Vue 的专属状态管理库,它允许我们跨组件或页面共享状态。它提供了比Vuex更简洁、更强大的API,同时完全兼容Vue 3的组合式API。学习理解和熟练的使用pinia是我们在以后的开发过程中必不可少的技能,点击下方链接查阅Pinia官方文档,让我们快速上手。
Pinia | The intuitive store for Vue.js (vuejs.org)
快速上手
安装Pinia
- 在你的安装包中安装pinia依赖包
node
npm install pinia
- 新建store文件夹,添加默认入口文件index.js,从刚安装的pinia依赖包中引入createPinia实例,并将他抛出。
index.js
import { createPinia } from 'pinia'
const store = createPinia()
export default store // 全局生效
注释:。在同一个模块中,可以使用多次export 语句来导出多个内容。每个模块只能有一个export default ,表示默认导出。当有多个export default
语句时,后面的会覆盖前面的
- 在mian.js中引入刚刚创建的文件中抛出的pinia状态管理库实例,并在VUE上use他。和当初学习路由一样的操作。
main.js
import store from '@/store'
createApp(App).use(store).mount('#app')
- 在store库中新建一个分库,我命名为user.js,我向pinia库中引入
defineStore
,将这个包实例化,可以在这个包中存储一些数据,将他向外抛出
-
defineStore 主要作用是定义和创建一个新的store实例,可以用来存储和管理全局状态或应用级别的数据
-
state:一个函数,返回一个对象,用于存储全局数据。
js
// 引入defineStore,存储全局的变量
import { defineStore } from 'pinia'
// 将全局变量定义为useUserStore并向外抛出
export const useUserStore = defineStore({
id: 'user',
// 在state中我写入了我的数据,这些数据可以在其他文件中引入
state: () => {
return {
userInfo: {
name: '绵绵冰',
age: 18,
sex:'女'
},
}
},
})
- 现在你可以在其他vue文件中引入你刚刚配置的数据
vue
<template>
<ul>
// 在此判断是否能成功引入你刚刚配置的数据
<li>姓名:{{ userStore.userInfo.name }}</li>
</ul>
</template>
<script setup>
// 引入你刚刚配置的数据
import { useUserStore } from "@/store/user";
// 实例化你引入的数据
const userStore = useUserStore();
console.log(userStore);
</script>
兄弟通讯实操运用
新建一个updata.vue文件,作为user.vue的兄弟文件,在根组件中引入updata.vue。 实现点击按钮时,改变数据中的name。
轻车熟路,我们直接通过@click
绑定函数,再使用userStore.userInfo.name = '绵绵冰2号'
将数据中的'绵绵冰'变成'绵绵冰2号'。但是这无疑还是会带来一个问题------------如果有很多兄弟组件同时更改这个属性时怎么办?这样的话还是会造成混乱。
actions
怎么解决这个问题?defineStore
中的actions
允许你在他其中内置函数,我们可以内置一个函数changeUserName,当点击事件触发时执行他。同样的,更改其他属性值也是一样,比如sex
store中的user.js
actions: {
changeUserName(name) {
this.userInfo.name = name
},
changeSex(sex) {
this.userInfo.sex = sex
}
}
updata.vue
// 兄弟组件中执行更改名字的操作
const changeName = () => {
// userStore.userInfo.name = '绵绵冰2号',这种方法不好
userStore.changeUserName('绵绵冰2号')
}
响应式
在更改属性中,例如在更改sex属性时,如果在组件user.vue中获取sex的方式是const sex = userStore.userInfo.sex
时,调用actions方法更改不会有效果,因为虽然仓库里的数据userStore.userInfo.sex是响应式的,但通过赋值后的sex却不是。在此处,我们有2个方法可以解决这个问题。
- 使用 computed 他会监听变量发生的改变并返回改变后的值
js
const sex = computed(() => { return userStore.userInfo.sex; });
- 使用 storeToRefs 他能使得传入的数据再赋值之后变为响应式
js
import { storeToRefs } from "pinia";
// userInfo里面的数据都变成了响应式
const { userInfo } = storeToRefs(userStore)
getters
getters是仓库中的计算属性,例如当你需要计算十年后你的年龄时你就可以使用 getters,在其中直接定义afterAge方法,在组件中直接通过 userStore.afterAge 调用。
js
// 仓库中的计算属性,专门用来获取 state
getters: {
afterAge(state) {
return state.userInfo.age + 10
}
}
persist本地存储
经过上文的一些更改手段,数据可以在前端得到改变,但是当页面刷新时数据又恢复了原样,如何使得更改后的数据持久化存在?
- 安装pinia-plugin-persist
node
npm i pinia-plugin-persist
- 在仓库中引入
js
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
export default store
- 进行本地存储
js
// 开启数据持久化,将数据存储进浏览器中
persist: {
enabled: true,
strategies: [
{
paths: ['userInfo'],
storage: localStorage,
}
]
}
经过上述操作,更改后的数据将会被存储在浏览器中不会被刷新