前言:在页面加入自适应是提高用户体验的一种形式,甚至有时候是手机用户,我们就需要做一个自适应处理,其中肯定会涉及一些状态条件的判断,而这些关键的条件就是我们用来切换样式的关键,所以我们需要使用状态管理工具vuex或者pinia进行存储这些状态,方便可以根据这些状态来控制显示和隐藏。
项目的使用:因为我们搭建的是vue3项目,推荐使用pinia,当然我也会简单介绍下vuex。
一、基本思路
1.显示页面:是由layout组件控制,则对这个组件进行自适应化。
2.在组件中设置一些状态通过v-if来控制某个组件的显示和隐藏,比如当设备过小时,隐藏侧边栏,使用一个小小的展开图标代替。
3.状态通过pinia来管理。
4.在组件挂载之前在window对象上加上resize方法监听页面的变化,再根据不同的变化配合pinia设置不同的状态并存储。
5.样式使用scss,样式做全局声明,变量化,方便统一修改和配置。
6.根据不同的设备尺寸变化设置、加载、切换不同的css样式。
二、vuex与pinia
Vuex 和 Pinia 都是 Vue 生态中用于状态管理的工具,简单说就是用来管理组件之间共享的数据(比如用户信息、购物车数据等)。它们解决的核心问题是:当多个组件需要使用同一数据时,如何让数据变更更清晰、更易维护。
2.1 Vuex(“老大哥”,Vue 2 时代主流)
Vuex 是 Vue 官方早期推出的状态管理库,主要用于 Vue 2,虽然也能在 Vue 3 中使用,但现在更推荐 Pinia。
1. 核心概念(必须掌握)
Vuex 的状态管理遵循 “单向数据流”,核心结构包含 5 个部分:
State:存储共享数据的地方(类似组件的
data
)。// 示例:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)const store = new Vuex.Store({state: {count: 0, // 共享的计数器user: null // 共享的用户信息} })
Mutations:唯一能修改
state
的地方,必须是同步函数(类似组件的methods
,但只能修改状态)。mutations: {increment(state) {state.count++ // 只能通过 mutation 修改 state},setUser(state, userInfo) {state.user = userInfo // 可以接收参数} }
Actions:处理异步操作(比如请求接口),最终通过调用
mutations
修改state
(不能直接改state
)。actions: {// 异步登录login(context, { username, password }) {return new Promise((resolve) => {// 模拟接口请求setTimeout(() => {const user = { id: 1, name: username }context.commit('setUser', user) // 调用 mutation 修改状态resolve(user)}, 1000)})} }
Getters:类似组件的
computed
,用于对state
进行加工处理(比如筛选、计算)。getters: {doubleCount(state) {return state.count * 2 // 计算 count 的两倍},isLogin(state) {return !!state.user // 判断用户是否登录} }
Modules:当状态太多时,拆分模块(比如拆成
user
模块、cart
模块)。modules: {user: {namespaced: true, // 开启命名空间,避免冲突state: { name: '' },mutations: { setName(state, name) { state.name = name } }} }
2. 如何在组件中使用?
读取
state
或getters
:<template><div>计数:{{ $store.state.count }}两倍计数:{{ $store.getters.doubleCount }}</div> </template>
调用
mutations
或actions
:<script> export default {methods: {add() {this.$store.commit('increment') // 调用 mutation},async login() {await this.$store.dispatch('login', { username: 'admin' }) // 调用 action}} } </script>
简化写法(推荐):用
mapState
、mapActions
等辅助函数:<script> import { mapState, mapActions } from 'vuex' export default {computed: {...mapState(['count']) // 映射 state.count 到组件的 count},methods: {...mapActions(['login']) // 映射 action login 到组件方法} } </script>
3. 优缺点
- 优点:成熟稳定,文档丰富,适合大型项目,支持严格模式(禁止直接修改
state
)。 - 缺点:
- 写法繁琐,需要定义
mutations
、actions
等,模板代码多。 - 对 TypeScript 支持差,类型推断不友好。
- 必须通过
this.$store
访问,不够灵活。
- 写法繁琐,需要定义
2.2 Pinia(“新宠”,Vue 3 官方推荐)
Pinia 是 Vue 官方推出的新一代状态管理库,由 Vuex 作者开发,现在是 Vue 3 推荐的状态管理方案,也支持 Vue 2。
1. 核心概念(比 Vuex 简单)
Pinia 简化了 Vuex 的设计,取消了 mutations
,只有 3 个核心概念:
- Store:一个存储状态的容器,每个模块对应一个
store
(类似 Vuex 的modules
,但更灵活)。 - State:存储数据的地方(和 Vuex 的
state
类似)。 - Actions:处理同步 / 异步操作,并直接修改
state
(合并了 Vuex 的mutations
和actions
)。 - Getters:类似 Vuex 的
getters
,用于计算状态。
2. 基本使用步骤
步骤 1:安装
npm install pinia --save
步骤 2:创建 Pinia 实例并挂载
在 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')
步骤 3:定义一个 Store(比如 store/counter.js
)
import { defineStore } from 'pinia'// 定义一个 store,命名规范:useXXXStore
export const useCounterStore = defineStore('counter', {// 状态(类似 data)state: () => ({count: 0,user: null}),// 计算属性(类似 computed)getters: {doubleCount: (state) => state.count * 2,isLogin: (state) => !!state.user},// 方法(同步/异步都可以,类似 methods)actions: {increment() {this.count++ // 直接修改 state(不需要 mutation)},// 异步操作async login(username, password) {// 模拟接口请求const user = await new Promise((resolve) => {setTimeout(() => resolve({ id: 1, name: username }), 1000)})this.user = user // 直接修改 state}}
})
3. 在组件中使用
<template><div>计数:{{ counterStore.count }}两倍计数:{{ counterStore.doubleCount }}<button @click="counterStore.increment">+1</button><button @click="handleLogin">登录</button></div>
</template><script setup>
import { useCounterStore } from '@/store/counter'// 获取 store 实例
const counterStore = useCounterStore()// 调用异步 action
const handleLogin = async () => {await counterStore.login('admin', '123456')
}
</script>
4. 高级用法
修改状态的其他方式:
// 方式1:直接修改 counterStore.count = 10// 方式2:批量修改(适合多个状态同时更新) counterStore.$patch({count: 10,user: { name: 'new name' } })// 方式3:通过函数修改(复杂逻辑) counterStore.$patch((state) => {state.count += 10state.user.name = 'new name' })
模块化:直接创建多个
store
文件即可(比如userStore.js
、cartStore.js
),无需像 Vuex 那样用modules
嵌套。持久化:配合
pinia-plugin-persistedstate
插件,轻松实现状态持久化(刷新页面不丢失):npm install pinia-plugin-persistedstate --save
// 在 store 中开启持久化 export const useUserStore = defineStore('user', {state: () => ({ user: null }),persist: true // 开启持久化,默认存储到 localStorage })
5. 优缺点
- 优点:
- 写法简洁,取消了
mutations
,直接在actions
中修改状态。 - 完美支持 TypeScript,类型推断友好。
- 支持 Vue 2 和 Vue 3,迁移成本低。
- 无需
this.$store
,直接导入store
实例使用,更灵活。 - 内置模块化,无需额外配置。
- 写法简洁,取消了
- 缺点:
- 相对较新,某些老项目可能还在使用 Vuex。
- 生态不如 Vuex 成熟(但主流功能都有替代方案)。
三、Vuex vs Pinia 核心区别
特性 | Vuex | Pinia |
---|---|---|
核心概念 | State、Mutations、Actions、Getters、Modules | State、Actions、Getters(无 Mutations,Modules 被 Store 替代) |
异步操作 | 必须在 Actions 中处理,通过 Mutations 修改状态 | 直接在 Actions 中处理并修改状态 |
TypeScript 支持 | 差 | 优秀 |
写法简洁度 | 繁琐(需定义 Mutations) | 简洁(直接修改状态) |
模块化 | 需要 modules 配置 | 每个 Store 就是一个模块 |
适用版本 | Vue 2 为主,Vue 3 兼容 | Vue 3 推荐,Vue 2 兼容 |
四、如何选择?
- 新项目(尤其是 Vue 3 + TypeScript):优先用 Pinia,写法简单,未来趋势。
- 老项目(Vue 2):如果已用 Vuex,继续维护即可;如果新开发,也可以用 Pinia(支持 Vue 2)。
- 团队熟悉 Vuex:如果团队对 Vuex 更熟练,且项目稳定,无需强制迁移。