注:本人使用vue3+js导入的pinia状态管理库,vue2请参考官方文档
pinia中文文档:https://pinia.web3doc.top/getting-started.html
第一步 使用 npm 或 yarn 安装
//使用npm安装
npm install pinia
//使用yarn安装
yarn add pinia
第二步
安装完成后需要在main.js入口文件中引入并使用
// 文件名main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
//1、在入口文件引入 pinia 并使用createPinia
import {createPinia } from 'pinia'
// 2、使用createPinia函数创建出 pinia的实例
const pinia = createPinia()
function bootstrap(){
const app = createApp(App)
app.use(router)
// 3、在把 pinia挂载在vue身上
app.use(pinia)
app.mount('#app')
}
bootstrap()
第三步
在src目录下创建store文件夹
创建完成后在store文件夹中创建.js为后缀的文件
第四步
4.1、在useOne.js中进行配置
// 1、引入并使用 defineStore 功能模块
import { defineStore } from 'pinia'
//2、创建一个容器 容器中有两个参数,参数一:容器的名称。参数二:容器的内容
//在pinia中只有 state getters actions
const useMainStore = defineStore('main', {
// pinia状态管理中的state 通过箭头函数返回一个对象
// state 相当于 vue中的data
state: () => {
return {
name: '张三',
age: 18
}
},
//getters相当于 computed计算属性 getters中是有缓存的
getters: {
},
//actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
actions: {
}
})
// 3、把容器暴露出去
export {
useMainStore
}
注意:
1、需要导入defineStore方法来创建pinia来创建容器;
2、defineStore方法有两个参数
1. 参数一:是一个字符串,自定义的容器名 (唯一的);
2.参数二:是一个对象,pinia的配置都在这里面;
3、给容器命名的规范一般是:
use+自定义的容器名+Store
;4、最后将创建的容器进行导出;
4.2、使用store
在src/components
目录下创建一个新的vue文件:son1.vue
<template>
<h2>{{mainStore.name}}</h2>
<h2>{{mainStore.age}}</h2>
<button @click="getStore">点击</button>
</template>
<script setup>
//1、导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
// 2、实例化容器
const mainStore = useMainStore()
//按钮点击事件
function getStore(){
console.log(mainStore.name + " " + mainStore.age);
}
</script>
<style lang="scss" scoped>
</style>
App.vue
<template>
<Son1 />
</template>
<script setup>
import Son1 from '@/components/son1.vue';
</script>
<style lang="scss" scoped>
</style>
在src/App.vue
主页面中导入上述组件,在页面中进行显示:
注意:store 是一个reactive 包裹的对象,所有访问其中的成员不需要 .value
4.3、解构state 数据
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<button @click="getStore">点击</button>
</template>
<script setup>
//1、导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
// 2、实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据
const { name, age } = mainStore
//按钮点击事件
function getStore() {
console.log(name + " " + age);
}
</script>
<style lang="scss" scoped>
</style>
来看下通过解构出来的state值和不通过解构得到的state值有什么区别:
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的{{ mainStore.age }}</h4>
<h4>通过解构获得的{{ age }}</h4>
<button @click="getStore">点击</button>
</template>
<script setup>
//1、导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
// 2、实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
const { name, age } = mainStore
//按钮点击事件
function getStore() {
mainStore.age++
}
</script>
<style lang="scss" scoped>
</style>
通过上图可以看到:获取到state中的数据不是响应式的
如果想要解构拿到 Store 中的响应式数据可以使用 storeToRefs
。
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4>
<button @click="getStore">点击</button>
</template>
<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
//按钮点击事件
function getStore() {
mainStore.age++
}
</script>
<style lang="scss" scoped>
</style>
此时可以看到页面的数据已经变了,通过 storeToRefs
方法包裹pinia实例,再通过解构获取的state就是响应式的了。
使用 actions
在src/store/useOne.js
文件中的pinia实例中,创建一个actions方法:
// 1、引入并使用 defineStore 功能模块
import { defineStore } from 'pinia'
//2、创建一个容器 容器中有两个参数,参数一:容器的名称。参数二:容器的内容
//在pinia中只有 state getters actions
const useMainStore = defineStore('main', {
// pinia状态管理中的state 通过箭头函数返回一个对象
// state 相当于 vue中的data
state: () => {
return {
name: '张三',
age: 18
}
},
//getters相当于 computed计算属性 getters中是有缓存的
getters: {
},
//actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
actions: {
**
addCount() {
this.age++
}
**
}
})
// 把容器暴露出去
export {
useMainStore
}
在src/components/App.vue
页面组件中进行pinia的actions方法的调用,此处有三种调用的方式:
方法一: 在标签中绑定actions事件
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4>
<button @click="getStore">点击</button>
**<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>**
</template>
<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
//按钮点击事件
function getStore() {
mainStore.age++
}
</script>
<style lang="scss" scoped>
</style>
方法二: 自定义一个方法,在这个方法中去调用对应的actions方法:
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4>
<button @click="getStore">点击</button>
<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
**<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>**
</template>
<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
//按钮点击事件
function getStore() {
mainStore.age++
}
**// 自定义的 count 加法方法
const addCount = () => {
mainStore.addCount()
}**
</script>
<style lang="scss" scoped>
</style>
方法三: pinia中提供了一个方法$patch,向上面两种方法调用actions去改变state的时候,会有留下state值的历史记录(时间旅行)。但是如果不通过actions,而是直接去修改state的值的话,例如直接通过mainStore.age++这种方式修改state的值,就不会留下state的历史记录。而$patch方法可以直接去修改state中的值,并且留下历史记录:
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4>
<button @click="getStore">点击</button>
<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
</template>
<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
//按钮点击事件
function getStore() {
mainStore.age++
}
// 自定义的 count 加法方法
const addCount = () => {
// mainStore.addCount()
**// $patch 方法,可以直接修改 state 中的值
mainStore.$patch({
name: "徐福",
age: 999,
})**
}
</script>
<style lang="scss" scoped>
</style>
点击前
点击后
使用方法三的语法应用某些更改确实很困难或成本很高: 任何集合修改(例如,从数组中推送、删除、拼接元素)都需要您创建一个新集合。正因为如此,该 $patch
方法还接受一个函数来对这种难以用补丁对象应用的改变进行分组:
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4>
<button @click="getStore">点击</button>
<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
</template>
<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
//按钮点击事件
function getStore() {
mainStore.age++
}
// 自定义的 count 加法方法
// const addCount = () => {
// // mainStore.addCount()
// // $patch 方法,可以直接修改 state 中的值
// mainStore.$patch({
// name: "徐福",
// age: 999,
// })
// }
const addCount = () => {
**// $patch 方法,通过分组改变 state 中的值
mainStore.$patch(state => {
state.name += '张三'
state.age++
})**
}
</script>
<style lang="scss" scoped>
</style>
你也可以完全自由地设置您想要的任何参数并返回任何内容。调用 actions 时,一切都会自动推断!
重置状态$reset
pinia的state更新的时候会有历史记录,即时间旅行,如果想要将数据重置到最开始更新数据的时候,pinia提供了一个方法:$reset
<template>
<h2>{{name}}</h2>
<h2>{{age}}</h2>
<h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4>
<button @click="getStore">点击</button>
<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
**<button @click="resetCount">重置 state</button>**
</template>
<script setup>
// 导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
// 解构获取state中的数据 解构出来的值不是响应式的
// 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
//按钮点击事件
function getStore() {
mainStore.age++
}
// 自定义的 count 加法方法
// const addCount = () => {
// // mainStore.addCount()
// // $patch 方法,可以直接修改 state 中的值
// mainStore.$patch({
// name: "徐福",
// age: 999,
// })
// }
const addCount = () => {
// $patch 方法,通过分组改变 state 中的值
mainStore.$patch(state => {
state.name += '张三'
state.age++
})
}
**// 重置 数据的方法
const resetCount = () => {
mainStore.$reset()
}**
</script>
<style lang="scss" scoped>
</style>
触发重置事件前
触发重置事件后
跨容器调用
1、在pinia中没有modules概念,可以在pinia中同时创建多个容器实例;可以在每一个容器中分别调用其他容器中的值,进行一些列的操作;
2、首先在src/store/useOne.js文件中创建一个新的容器,在新的容器中可以在actions中,获取到其他容器实例,调用其中的state值
// 1、引入并使用 defineStore 功能模块
import { defineStore } from 'pinia'
//2、创建一个容器 容器中有两个参数,参数一:容器的名称。参数二:容器的内容
//在pinia中只有 state getters actions
const useMainStore = defineStore('main', {
// pinia状态管理中的state 通过箭头函数返回一个对象
// state 相当于 vue中的data
state: () => {
return {
name: '张三',
age: 18
}
},
//getters相当于 computed计算属性 getters中是有缓存的
getters: {
},
//actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
actions: {
addCount() {
this.age++
}
}
})
const useProjectStore = defineStore('project', {
// pinia状态管理中的state 通过箭头函数返回一个对象
// state 相当于 vue中的data
state: () => {
return {
username: '李四',
count: 21
}
},
//getters相当于 computed计算属性 getters中是有缓存的
getters: {
},
//actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
actions: {
// 1、加法方法
addAge() {
// 实例化 pinia 容器
const mainState = useMainStore()
this.count += this.count + mainState.age
}
}
})
// 把容器暴露出去
export {
useMainStore,
useProjectStore
}
3、在组件中可以有两种方法去调用pinia中跨容器调用的方法:
方法一: 直接在标签中去调用容器中的方法
<template>
<!-- <h2>{{name}}</h2> -->
<!-- <h2>{{age}}</h2> -->
<!-- <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4> -->
<!-- <button @click="getStore">点击</button>
<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
<button @click="resetCount">重置 state</button> -->
**<h2>{{count}}</h2>**
**<button @click="projectStore.addAge">模板跨容器调用</button>**
</template>
<script setup>
// 导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore ,useProjectStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
**const projectStore = useProjectStore()**
// 解构获取state中的数据 解构出来的值不是响应式的
// 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
**const { username, count } = storeToRefs(projectStore)**
//按钮点击事件
// function getStore() {
// mainStore.age++
// }
// 自定义的 count 加法方法
// const addCount = () => {
// // mainStore.addCount()
// // $patch 方法,可以直接修改 state 中的值
// mainStore.$patch({
// name: "徐福",
// age: 999,
// })
// }
// const addCount = () => {
// // $patch 方法,通过分组改变 state 中的值
// mainStore.$patch(state => {
// state.name += '张三'
// state.age++
// })
// }
// 重置 数据的方法
// const resetCount = () => {
// mainStore.$reset()
// }
</script>
<style lang="scss" scoped>
</style>
触发事件前
触发事件后
方法二: 自定义一个调用容器方法的函数c
<template>
<!-- <h2>{{name}}</h2> -->
<!-- <h2>{{age}}</h2> -->
<!-- <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
<h4>通过解构获得的---{{ age }}</h4> -->
<!-- <button @click="getStore">点击</button>
<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
<button @click="resetCount">重置 state</button> -->
<h2>{{count}}</h2>
<button @click="projectStore.addAge">模板跨容器调用</button>
**<button @click="addAge">自定义方法跨容器调用</button>**
</template>
<script setup>
// 导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';
//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore ,useProjectStore } from '../store/useOne'
//实例化容器
const mainStore = useMainStore()
const projectStore = useProjectStore()
// 解构获取state中的数据 解构出来的值不是响应式的
// 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
const { username, count } = storeToRefs(projectStore)
//按钮点击事件
// function getStore() {
// mainStore.age++
// }
// 自定义的 count 加法方法
// const addCount = () => {
// // mainStore.addCount()
// // $patch 方法,可以直接修改 state 中的值
// mainStore.$patch({
// name: "徐福",
// age: 999,
// })
// }
// const addCount = () => {
// // $patch 方法,通过分组改变 state 中的值
// mainStore.$patch(state => {
// state.name += '张三'
// state.age++
// })
// }
// 重置 数据的方法
// const resetCount = () => {
// mainStore.$reset()
// }
// 自定义的 加法方法
**const addAge = () => {
projectStore.count += mainStore.age
}**
</script>
<style lang="scss" scoped>
</style>
触发前
触发后
actions 的操作
const changeStore = () => {
// 方式四:逻辑比较多的时候可以封装到 actions 做处理
// 封装好 actions 之后,直接调用
mainStore.adds(10)
}
- 封装 actions:
-
// 类似与组件的 methods ,封装业务逻辑,修改 state actions: { // 注意:不能使用箭头函数定义action,因为箭头函数绑定外部this adds(num) { this.count = this.count + num this.foo++ // 同样建议使用 $patch() // this.$patch({}) // this.Spatch(state = {……}) } }
注意:像上面的跨容器调用的时候,将每一个容器都放在同一个文件中了,最好的做法需要将每个容器单独写一个文件。
本文借鉴CSDN博主「凉爽爽爽爽爽爽爽爽爽」的原创文章
原文链接:https://blog.csdn.net/qq_45770253/article/details/123509563