一、Pinia的安装
Pinia是Vue的专属状态管理库,它允许你跨组件或页面共享状态。
1、安装语法:npm install pinia 、 pnpm add pinia
2、创建一个pinia(根存储)并将其传递给应用程序
main.js
import { createApp } from 'vue'
import App from './App.vue'
// 引入 createPinia 函数
import { createPinia } from 'pinia'
const app = createApp(App)
// 使用 createPinia() 来创建 Pinia(根存储),并应用到整个应用中
app.use(createPinia())
app.mount('#app')
3.工作流程

二、Pinia中的store
1、store是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定;换句话说,它承载着全局状态;它有点像一个永远存在的组件,每个组件都可以读取和写入它
2、store它有三个概念:state、getters和actions,我们可以理解成组件中的data、computed和methods
3、在项目中的src目录下建立store文件夹,在其下面建立store.js文件
4、store是用defineStore(name, function | options)定义的,建议其函数返回的值命名为use...Store方便理解
a. 参数name:名字,必填值且唯一
b. 参数function|options:可以是对象或函数形式
■ 对象形式【选项模式】,其中配置state、getters和actions选项
■ 函数形式【组合模式,类似组件组合式API的书写方式】,定义响应式变量和方法,并且return对应的变量和方法;ref()相当于state,computed()相当于getters,function()相当于actions
src/store/store.js
import { defineStore } from "pinia";
import { computed,ref } from 'vue'
//创建store,并暴露出去
//参数一:名字,必填值且唯一
//参数二:组合式书写方式采用函数形式
export const useStore = defineStore('main',()=>{
//ref变量 --- state
//computed() 计算属性 --- getters
//functions 函数 --- actions
return {
//暴露出去的变量、函数、计算属性即可
}
})
三、store中的state
state是store的核心部分,主要存储的是共享的数据。
(一)定义state
1、store采用的是选项式模式时,state选项为函数返回的对象,在其定义共享的数据
2、store采用的是组合式模式时,在其函数内定义的ref变量,最终return出去来提供共享的数据
src/store/useUserStore.js
import { defineStore } from "pinia";
import { ref } from 'vue'
export const useUserStore = defineStore('user',()=>{
const age = ref(27)
const level = ref(5)
const account = ref('SD78906')
const nickname = ref('一个好人')
//将数据暴露出去,共享给需要的组件
return {
age,level,account,nickname
}
})
(二)组件中访问state
在组合式 API 组件中,直接引入对应的store,通过store对象直接获取和修改state
提示:
如果想在组件中自定义变量来接收store中的state中共享的数据,我们可以这样做:
● 使用computed(() => store.dataName),具有响应式,但是只读形式
● 使用storeToRefs(store)从store解构想要的state,具有响应式,可直接修改,可自定义名称
App.vue
<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import UserVue from '@/components/User.vue'
//获取UserStore实例
const user_store = useUserStore()
//通过computed()将store中state映射成当前组件中的计算属性,具有响应性,但是是只读的
const user_age = computed(() => user_store.age)
const user_level = computed(() => user_store.level)
const user_account = computed(() => user_store.account)
const user_nickname = computed(() => user_store.nickname)
//storeToRefs将store中state解构为组件的数据,具有响应性,还可以响应式修改
const {
age,
level,
account: userAccount,
nickname: userNickname
} = storeToRefs(user_store)
</script>
<!-- 视图区域(view) -->
<template>
<UserVue></UserVue>
<h2>从store直接取state</h2>
<ul>
<li>年龄:{{ user_store.age }}</li>
<li>等级:{{ user_store.level }}</li>
<li>账号:{{ user_store.account }}</li>
<li>昵称:{{ user_store.nickname }}</li>
</ul>
<button @click="user_store.age += 10">更改年龄</button>
<button @click="user_store.nickname += '='">更改昵称</button>
<hr>
<h2>computed映射为计算属性</h2>
<ul>
<li>年龄:{{ user_age }}</li>
<li>等级:{{ user_level }}</li>
<li>账号:{{ user_account }}</li>
<li>昵称:{{ user_nickname }}</li>
</ul>
<button @click="user_age += 10">更改年龄</button>
<button @click="user_nickname += '='">更改昵称</button>
<hr>
<h2>storeToRefs解构成自己的数据</h2>
<ul>
<li>年龄:{{ age }}</li>
<li>等级:{{ level }}</li>
<li>账号:{{ userAccount }}</li>
<li>昵称:{{ userNickname }}</li>
</ul>
<button @click="age += 10">更改年龄</button>
<button @click="userNickname += '='">更改昵称</button>
</template>
<style>
</style>
User.vue
<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'
const user_store = useUserStore()
const {
age,
level,
account: userAccount,
nickname: userNickname
} = storeToRefs(user_store)
</script>
<template>
<ul>
<li>年龄:{{ age }}</li>
<li>等级:{{ level }}</li>
<li>账号:{{ userAccount }}</li>
<li>昵称:{{ userNickname }}</li>
</ul>
</template>
<style scoped>
ul {
background-color: yellow;
}
</style>
四、store中的getters
getters是计算得到的新的共享数据,当依赖的数据发生变化时则重新计算,所以其他组件包括store自己不要直接对其修改。
(一)定义Getters
1、store采用的是选项式模式时,getters选项中声明的函数即为计算属性
a. 在其函数内可通过this关键字来获取store实例,也可通过方法的第一个参数得到store实例
b. 如果采用的是箭头函数的话,无法使用this关键字,为了更方便使用store中实例,可为其箭头函数设置第一个参数来获取store实例
2、store采用的是组合式模式时,可通过computed()函数通过计算得到新的数据,再将其return暴露出去即可
import { defineStore } from "pinia"
import { computed, ref } from "vue"
export const useUserStore = defineStore('user', () => {
const birthday = ref('1992-12-27')
const age = ref(30)
// 声明通过计算得到的共享数据,是只读的,如果依赖的数据发生变化则会重新计算
const month = computed(() => {
return birthday.value.split('-')[1]
})
const ageStage = computed(() => {
if (age.value < 18) return '未成年'
if (age.value < 35) return '青年'
if (age.value < 50) return '中年'
if (age.value >= 50) return '老年'
})
return { birthday, age, month, ageStage }
})
(二)在组件中使用Getters
1、选项式API的组件中,访问store中的getters和访问state类似,同样可使用mapState()帮助器将getters属性映射为只读计算属性
注意:如果采用mapWritableState()帮助器将store中的getters映射为组件内部的计算属性,依旧可以具有响应式,一旦对其进行修改则会报错
2、在组合式API组件中,访问store中的getters和访问state类似,直接引入对应的store,通过store对象直接获取getters,但是如果对其进行修改则会报错
提示:
如果想将store中的getter中共享的数据映射为本地组件的计算属性,我们可以这样做:
● 使用computed(() => store.getterName),具有响应式,但是只读形式
● 使用storeToRefs(store)从store解构getter依旧是计算属性,所以是只读的,一旦对其进行修改则会报错,但是具有响应式,可自定义名称
实例:
src/store/useUserStore.js
import { defineStore } from "pinia";
import { computed,ref } from 'vue'
export const useUserStore = defineStore('user',()=>{
const birthday = ref('1992-12-27')
const age = ref(30)
//声明通过计算得到的共享数据,是只读的,如果依赖的数据发生变化则会重新计算
const month = computed(()=>{
return birthday.value.split('-')[1]
})
const ageState = computed(()=>{
if(age.value < 18) return '未成年'
if(age.value < 35) return '青年'
if(age.value < 50) return '中年'
if(age.value >= 50) return '老年'
})
//将数据暴露出去,共享给需要的组件
return {
birthday,age,month,ageState
}
})
App.vue
<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
//获取UserStore实例,可直接通过store获取getters,但是是只读的,如果一旦修改则会报错
const user_store = useUserStore()
//通过computed()将store中getters映射成当前组件中的计算属性,但是是只读的,如果一旦修改则会报错
const birthday_month = computed(() => user_store.month)
const user_age_state = computed(() => user_store.ageState)
//storeToRefs将store中getters解构为组件的数据,具有响应性,但是是只读的,如果一旦修改则会报错
const {
month,
ageState: userAgeState
} = storeToRefs(user_store)
//将state解构为自己的数据
const { birthday,age } = storeToRefs(user_store)
</script>
<!-- 视图区域(view) -->
<template>
<h3>通过store直接获取getters</h3>
<ul>
<li>月份:{{ user_store.month }}</li>
<li>年龄阶段:{{ user_store.ageState }}</li>
</ul>
<button @click="user_store.month = '5'">更改月份</button>
<button @click="user_store.ageState = '未知'">更改年龄阶段</button>
<hr>
<h3>通过computed将getters映射为自己的计算属性</h3>
<ul>
<li>月份:{{ birthday_month }}</li>
<li>年龄阶段:{{ user_age_state }}</li>
</ul>
<button @click="birthday_month = '5'">更改月份</button>
<button @click="user_age_state = '未知'">更改年龄阶段</button>
<hr>
<h3>通过storeToRefs将getters映射为自己的计算属性</h3>
<ul>
<li>月份:{{ month }}</li>
<li>年龄阶段:{{ userAgeState }}</li>
</ul>
<button @click="month = '5'">更改月份</button>
<button @click="userAgeState = '未知'">更改年龄阶段</button>
<hr>
生日:<input type="date" v-model="birthday">
年龄:<input type="number" min="1" max="120" v-model="age">
</template>
<style>
</style>
五、store中的actions
actions一般情况下是对state中的数据进行修改的业务逻辑函数,actions也可以是异步的,您可以在其中await任何API调用甚至其他操作!
(一)定义Actions
1、store采用的是选项式模式时,actions选项中声明的函数即可共享其函数,在其函数内可通过this来获取整个store实例
2、store采用的是组合式模式时,可通过声明函数,再将其return暴露出去即可共享其函数
import {defineStore} from "pinia"
import {ref} from "vue";
export const useUserStore = defineStore('user', () => {
const nickname = ref('自古风流')
const age = ref(20)
// 定义函数(注意:形参不要和 ref 名冲突)
function setUserInfo(user_nickname, user_age) {
nickname.value = user_nickname
age.value = user_age
}
function setUserInfoByObject(user) {
// 可通过 `this` 来获取当前 store 实例
nickname.value = user.nickname
age.value = user.age
}
return {nickname, age, setUserInfo, setUserInfoByObject} // 暴露函数即可共享函数
})
(二)组件中访问Actions
1、在选项式 API 组件中,可以使用mapActions(storeObj, array | object)帮助器将actions映射为当前组件的函数
a. storeObj引入的store对象
b. array | object:字符串数组形式或者对象形式
■ 【字符串数组形式】直接将store中actions的函数映射为当前组件的函数,但是不能自定义名称
■ 【对象形式时】key为自定义当前组件的函数名,value字符串形式,是store中actions的函数名
2、在组合式API组件中,直接引入对应的store,通过store对象直接获取actions
提示:如果想将store中的actions中函数映射为本地组件的函数,可将store解构出对应的函数即可,也可自定应函数名,此处不可通过storeToRefs(store)函数
实例:
useUserStore.js
import { defineStore } from "pinia";
import { computed,ref } from 'vue'
export const useUserStore = defineStore('user',()=>{
const nickname = ref('一个好人')
const age = ref(20)
//定义函数(注意:形参不要和ref名冲突)
function setUserInfo(user_nickname,user_age) {
nickname.value = user_nickname
age.value = user_age
}
function setUserInfoByObject(user) {
//可通过this来获取当前store实例
nickname.value = user.nickname
age.value = user.age
}
//将数据暴露出去,共享给需要的组件
return {
nickname,age,setUserInfo,setUserInfoByObject
}
})
App.vue
<script setup>
import { useUserStore } from '@/store/useUserStore'
import { storeToRefs } from 'pinia'
//获取UserStore实例
const user_store = useUserStore()
const {nickname,age} = storeToRefs(user_store)
//可将store中的actions映射为自己的函数,可自定义映射的函数名(不可使用storeToRefs函数)
const {setUserInfo,setUserInfoByObject:set_user_info_object} = user_store
</script>
<!-- 视图区域(view) -->
<template>
<ul>
<li>昵称:{{ nickname }}</li>
<li>年龄:{{ age }}</li>
</ul>
<span>直接使用store执行actions:</span>
<button @click="user_store.setUserInfo('Tom',15)">修改信息</button>
<button @click="user_store.setUserInfoByObject({nickname: 'John',age: 40})">修改信息</button>
<hr>
<span>将store中的actions映射成自己的函数:</span>
<button @click="setUserInfo('Mike',35)">修改信息</button>
<button @click="set_user_info_object({nickname: 'Yadown',age: 20})">修改信息</button>
</template>
<style>
</style>
1278

被折叠的 条评论
为什么被折叠?



