Pinia — 全局状态管理
博客的"收藏夹"被首页、文章详情、侧边栏多个组件共用:某处点了收藏,其它组件要立即同步。靠 props 层层传递既繁琐又难维护,这需要全局状态管理。Pinia 是 Vue3 官方推荐的状态库,本节用它实现收藏功能。
安装并启用 Pinia
安装:npm install pinia。然后在 main.js 中注册:
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia()) // 启用 Pinia
app.mount('#app')
创建 Store:state / getters / actions
Store 集中管理共享状态,建 stores/favorites.js:
// stores/favorites.js
import { defineStore } from 'pinia'
export const useFavoritesStore = defineStore('favorites', {
state: () => ({ ids: [] }), // 收藏的文章 id 列表
getters: {
isFavorite: (state) => (id) => state.ids.includes(id), // 是否已收藏
count: (state) => state.ids.length // 收藏总数
},
actions: {
toggle(id) { // 收藏或取消收藏
const i = this.ids.indexOf(id)
i === -1 ? this.ids.push(id) : this.ids.splice(i, 1)
}
}
})
在组件中使用 Store
任意组件调用同一个 useFavoritesStore,拿到的都是同一份数据。完整 SFC 如下:
<!-- ArticleCard.vue -->
<script setup>
import { useFavoritesStore } from '../stores/favorites'
import { storeToRefs } from 'pinia'
const props = defineProps(['post'])
const store = useFavoritesStore()
const { isFavorite, count } = storeToRefs(store) // 解构后仍响应式
function onCollect() {
store.toggle(props.post.id) // 调用 action 修改全局状态
}
</script>
<template>
<button @click="onCollect">{{ isFavorite(props.post.id) ? '已收藏' : '收藏' }}</button>
<span>共 {{ count }} 篇收藏</span>
</template>
在任何组件点击收藏,其它组件里的 isFavorite 与 count 会立即更新,因为它们读的是同一个 store。
组合式写法(Setup Store)
Pinia 也支持组合式 API 风格的 Store,更像写 Composable:
// 等价写法:第二个参数改为函数
export const useFavoritesStore = defineStore('favorites', () => {
const ids = ref([])
const count = computed(() => ids.value.length)
const isFavorite = (id) => ids.value.includes(id)
function toggle(id) {
const i = ids.value.indexOf(id)
i === -1 ? ids.value.push(id) : ids.value.splice(i, 1)
}
return { ids, count, isFavorite, toggle } // 记得 return 出去
})
两种写法可共存,项目里选择一种保持统一即可。
数据持久化:存到 localStorage
刷新页面 store 会重置,收藏就丢了。监听 ids 同步到本地存储:
import { watch } from 'vue'
import { useFavoritesStore } from './stores/favorites'
const store = useFavoritesStore()
const saved = localStorage.getItem('fav_ids') // 启动时恢复
if (saved) store.ids = JSON.parse(saved)
watch(store.ids, (ids) => { // 每次变化都写回
localStorage.setItem('fav_ids', JSON.stringify(ids))
}, { deep: true })
刷新后收藏依然在,体验更接近原生应用。 小结:Pinia 用 Store 集中管理共享状态,state 存数据、getters 派生、actions 修改,配合 localStorage 可持久化。项目开发完成,下一节讲打包与部署上线。