
参考资料:
1. pinia 新状态管理库(★)
Pinia官网 - 符合直觉的 Vue.js 状态管理库 - 类型安全、可扩展性以及模块化设计。 甚至让你忘记正在使用的是一个状态库。
- 类型自动推断
- 支持 vue2 和 vue3
- 极致轻量大小只有 1kb 左右
Pinia API与Vuex(≤4)也有很多不同,即:
mutotion 已被弃用。它们经常被认为是极其冗余的。它们初衷是带来 devtools 的集成方案,但这已不再是一个问题了。
无需要创建自定义的复杂包装器来支持TypeScript,一切都可标注类型,API的设计方式是尽可能地利用TS类型推理。
无过多的魔法字符串注入。只需要导入函数并调用它们,然后享受自动补全的乐趣就好。
无需要动态添加Store,它们默认都是动态的,甚至你可能都不会注意到这点。注意,你仍然可以在任何时候手动使用一个Store来注册它,但因为它是自动的,所以你不需要担心它。
不再有嵌套结构的模块。你仍然可以通过导入和使用另一个Store来隐含地嵌套stores空间。虽然Pinia从设计上提供的是一个扁平的结构,但仍然能够在Store之间进行交叉组合。你甚至可以让 stores有循环依赖关系。
不再有可命名的模块。考虑到Store的扁平架构,Store的命名取决于它们的定义方式,你甚至可以说所有Store都应该命名。
1.1 安装和导入
安装:npm i pinia
使用:
- 导入:main.js
1 2 3 4 5 6 7 8
| import { createApp } from 'vue' import './style.css' import App from './App.vue' import { createPinia } from 'pinia'
createApp(App) .use(createPinia()) .mount('#app')
|
1.2 使用 option 风格
store 模块独立定义,独立维护。
state,公共状态字段,格式 state: () => { return { xx:xx, ...} } 或 state: () => ({ xx:xx, ... })
getters,计算属性,格式 getters: { 计算属性(state) {...} }
actions,维护修改公共状态字段的方法,支持同步和异步,格式:actions: { func(v) { this.xx = v }}
目录:
1 2 3 4 5
| src/ store/ moduleAStore.js moduleBStore.js ...
|
src/store/tabbarStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import { defineStore } from "pinia";
const useTabbarStore = defineStore("tabbar", { state: () => { return { count: 0, isTabbarShow: true } }, getters: { doubleCount(state) { return state.count * 2 }, }, actions: { change(value) { this.isTabbarShow = value } } })
export default useTabbarStore
|
App.vue - 此风格常用
1 2 3 4 5 6 7 8 9 10 11 12
| <template> <div class="box"> <Tabbar v-show="store.isTabbarShow"></Tabbar> </div> </template>
<script setup> import Tabbar from "./components/Tabbar.vue" import useTabbarStore from "./store/tabbarStore";
const store = useTabbarStore() //然后js或dom中就直接 store.公共状态 访问或修改均可,拥有响应性 </script>
|
选项式使用 pinia - 老的使用风格
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div class="box"> <Tabbar v-show="isTabbarShow"></Tabbar> </div> </template>
<script setup> import useTabbarStore from "./store/tabbarStore"; export default { computed: { ...mapState(useTabbarStore, ["isTabbarShow"]) //从 useTabbarStore 解构出来,此时可直接使用,无需 store. } } </script>
|
store.$patch({ key:value }) 对部分的值进行补丁式修改(同名覆盖、其他合并)
store.$reset() 重置store为默认值
1.3 使用 setup 风格(★)
完全是钩子函数封装的写法,包括 watch 也可以写在这块逻辑中。
src/store/tabbarStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { defineStore } from "pinia"; import { ref } from "vue";
const useTabbarStore = defineStore("tabbar", () => { const isTabbarShow = ref(true) const change = (value) => { isTabbarShow.value = value } return { isTabbarShow, change } })
export default useTabbarStore
|
src/store/cinemasStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import { defineStore } from "pinia"; import { ref } from "vue";
const useCinemasStore = defineStore("cinemas", () => { const cinemaList = ref([]) const getCinemaList = async () => { let res = await axios({ url: 'https://api', headers: { 'x': 'y' } }) cinemaList.value = res.data.data.cinemas } const computedCinemaList = computed(() => (type) => { return cinemaList.value.filter(item => item.type === type) } ) return { cinemaList, getCinemaList, computedCinemaList } })
export default useCinemasStore
|
1.4 actions 异步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const useUsers = defineStore('users', { state: () => ({ userData: null, }), actions: { async registerUser(login, password) { try { this.userData = await api.post({ login, password }) showTooltip(`欢迎回来 ${this.userData.name}!`) } catch (error) { showTooltip(error) return error } }, }, }) export default useUsers
|
1.5 跨store使用
src/store/cityStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { defineStore } from "pinia"; import { ref } from "vue";
const useCityStore = defineStore("city", () => { const cityId = ref(110100) const cityName = ref("北京") const changeCity = (id, name) => { cityId.value = id cityName.value = name }
return { cityId, cityName, changeCity } })
export default useCityStore
|
src/store/cinemasStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import { defineStore } from "pinia"; import { ref } from "vue"; import useCityStore from "./cityStore"; const cityStore = useCityStore()
const useCinemasStore = defineStore("cinemas", () => { const cinemaList = ref([]) const getCinemaList = async () => { let res = await axios({ url: `https://api?cityId=${cityStore.cityId}`, headers: { 'x': 'y' } }) cinemaList.value = res.data.data.cinemas } const computedCinemaList = computed(() => (type) => { return cinemaList.value.filter(item => item.type === type) } ) return { cinemaList, getCinemaList, computedCinemaList } })
export default useCinemasStore
|
2. pinia 持久化插件
地址:https://www.npmjs.com/package/pinia-plugin-persistedstate
安装:npm i pinia-plugin-persistedstate
使用:
main.js
1 2 3 4 5
| import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia() pinia.use(piniaPluginPersistedstate)
|
xxxStore.js - 在 defineStore 的第三个参数,持久化开启 { persist: true }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import {defineStore} from 'pinia' import { ref } from 'vue'
export const useUserStore = defineStore("user", () => { const user = ref({}) const changeUser = (value) => { user.value = value } return { user, changeUser } }, { persist: true })
|
触发持久化 store 时,会将公共状态数据 user 存储在 localStorage 中。