✅ Vuex 模块化示例
📁 项目结构
store/
├── index.js
├── modules/
│ ├── user.js
│ └── counter.js
🔸 1. store/modules/user.js
export default {
state: () => ({
name: '张三',
loggedIn: false,
}),
getters: {
welcomeMessage(state) {
return state.loggedIn ? `欢迎你,${state.name}` : '请先登录';
}
},
mutations: {
login(state, name) {
state.loggedIn = true;
state.name = name;
},
logout(state) {
state.loggedIn = false;
state.name = '';
},
},
actions: {
loginAsync({ commit }, name) {
setTimeout(() => {
commit('login', name);
}, 1000);
}
}
};
🔸 2. store/modules/counter.js
export default {
state: () => ({
count: 0,
}),
getters: {
double(state) {
return state.count * 2;
}
},
mutations: {
increment(state) {
state.count++;
}
}
};
🔸 3. store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import user from './modules/user';
import counter from './modules/counter';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user,
counter
}
});
组件中使用
<template>
<div>
<p>用户名:{{ $store.state.user.name }}</p>
<p>登录状态:{{ $store.state.user.loggedIn ? '已登录' : '未登录' }}</p>
<p>{{ $store.getters['user/welcomeMessage'] }}</p>
<hr>
<p>当前计数:{{ $store.state.counter.count }}</p>
<p>双倍:{{ $store.getters['counter/double'] }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
export default {
methods: {
increment() {
this.$store.commit('counter/increment');
}
},
mounted() {
this.$store.dispatch('user/loginAsync', '李四');
this.increment();
}
};
</script>
<template>
<div>
<p>用户名:{{ name }}</p>
<p>登录状态:{{ loggedIn ? '已登录' : '未登录' }}</p>
<p>{{ welcomeMessage }}</p>
<hr>
<p>当前计数:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
export default {
computed: {
...mapState('user', ['name', 'loggedIn']),
...mapGetters('user', ['welcomeMessage']),
...mapState('counter', ['count']),
...mapGetters('counter', ['double']),
},
methods: {
...mapMutations('counter', ['increment']),
...mapActions('user', ['loginAsync']),
},
mounted() {
this.loginAsync('李四');
this.increment();
}
};
</script>
✅ Pinia 模块化示例
📁 项目结构
stores/
├── index.js
├── user.js
└── counter.js
🔸 1. stores/user.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
name: '张三',
loggedIn: false,
}),
getters: {
welcomeMessage: (state) =>
state.loggedIn ? `欢迎你,${state.name}` : '请先登录'
},
actions: {
login(name) {
this.name = name;
this.loggedIn = true;
},
logout() {
this.name = '';
this.loggedIn = false;
},
loginAsync(name) {
setTimeout(() => {
this.login(name);
}, 1000);
}
}
});
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useUserStore = defineStore('user', () => {
const name = ref('张三');
const loggedIn = ref(false);
const welcomeMessage = computed(() =>
loggedIn.value ? `欢迎你,${name.value}` : '请先登录'
);
function login(newName) {
name.value = newName;
loggedIn.value = true;
}
function logout() {
name.value = '';
loggedIn.value = false;
}
function loginAsync(newName) {
setTimeout(() => {
login(newName);
}, 1000);
}
return {
name,
loggedIn,
welcomeMessage,
login,
logout,
loginAsync
};
});
🔸 2. stores/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
double: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
}
}
});
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const double = computed(() => count.value * 2);
function increment() {
count.value++;
}
return {
count,
double,
increment
};
});
🔸 3. stores/index.js(创建 pinia 实例)
import { createPinia } from 'pinia';
const pinia = createPinia();
export default pinia;
组件中使用
<template>
<div>
<p>用户名:{{ name }}</p>
<p>登录状态:{{ loggedIn ? '已登录' : '未登录' }}</p>
<p>{{ welcomeMessage }}</p>
<hr>
<p>当前计数:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { storeToRefs } from 'pinia';
import { useUserStore } from '@/stores/user';
import { useCounterStore } from '@/stores/counter';
const userStore = useUserStore();
const counterStore = useCounterStore();
// 保持响应式解构
const { name, loggedIn, welcomeMessage } = storeToRefs(userStore);
const { count, double } = storeToRefs(counterStore);
// 方法直接调用
userStore.loginAsync('李四');
counterStore.increment();
</script>
🔄 Vuex → Pinia 核心差异对照
| Vuex | Pinia |
|---|
modules | 每个 defineStore 就是一个模块 |
state.moduleName.xxx | store.xxx |
mutations + actions 分离 | actions 直接修改状态 |
mapState / mapGetters 解构 | storeToRefs() 保持响应式解构 |
dispatch / commit | 直接调用方法,如 store.loginAsync() |