参考:官方文档:https://vuex.vuejs.org/zh/
一个简单的求和案例
点击按钮当前求和+1
<!-- App.vue -->
<template>
<Count></Count>
</template>
<script>
import { ref } from 'vue';
import Count from './components/Count.vue'
export default {
name: 'App',
components: {
Count
},
setup(){
return{
}
}
}
</script>
<style></style>
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne">+1</button>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'Count',
setup(){
let sum = ref(0)
function addOne(){
sum.value = sum.value+1
}
return {
sum,
addOne
}
}
}
</script>
<style>
</style>
使用vuex实现
<!-- App.vue -->
<template>
<Count></Count>
</template>
<script>
import { } from 'vue'
import Count from './components/Count.vue'
import { useStore } from 'vuex' // 引入useStore 方法
export default {
name: 'App',
components: {
Count
},
setup(){
const store = useStore()
return{
}
}
}
</script>
<style></style>
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne">+1</button>
</template>
<script>
import { ref } from 'vue';
import { useStore } from 'vuex' // 引入useStore 方法
export default {
name: 'Count',
setup(){
const store = useStore()
console.log(store)
let sum = ref(0)
function addOne(){
store.commit('incrementOne')
sum.value = store.state.sum
}
return {
sum,
addOne
}
}
}
</script>
<style>
</style>
// store/index.js
import {createStore} from 'vuex'
const actions = {
}
const mutations = {
incrementOne(state){
state.sum++
}
}
const state = {
sum: 0
}
export default createStore({
actions,
mutations,
state
})
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
上面我们虽然实现了求和案例,但是我们不能再模板中直接使用state中的值,同时,我们可以通过计算属性实现
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne">+1</button>
<h1>{{sum}}</h1>
</template>
<script>
import { ref, computed } from 'vue';
import { useStore, mapState } from 'vuex' // 引入useStore 方法
export default {
name: 'Count',
setup(){
const store = useStore()
console.log(store)
let sum = ref(0)
function addOne(){
store.commit('incrementOne')
// sum.value = store.state.sum
}
sum = computed(()=>{return store.state.sum})
// bigSum = computed(() => {return sum*10})
return {
sum,
addOne
}
},
}
</script>
<style>
</style>
使用mapState实现
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne">+1</button>
<h1>{{sum}}</h1>
</template>
<script>
import { ref, computed } from 'vue';
import { useStore, mapState } from 'vuex' // 引入useStore 方法
export default {
name: 'Count',
setup(){
const store = useStore()
console.log(store)
// let sum = ref(0)
function addOne(){
store.commit('incrementOne')
// sum.value = store.state.sum
}
// bigSum = computed(() => {return sum*10})
return {
// sum,
addOne
}
},
computed:{
...mapState(['sum'])
}
}
</script>
<style>
</style>
Getter
有时候我们需要从 store 中的 state 中派生出一些状态,例如,我们需要得到sum变大10倍后的值。
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne">+1</button>
<h1>{{bigSum}}</h1>
</template>
<script>
import { ref, computed } from 'vue';
import { useStore, mapState, mapGetters } from 'vuex' // 引入useStore 方法
export default {
name: 'Count',
setup(){
const store = useStore()
console.log(store)
// let sum = ref(0)
function addOne(){
store.commit('incrementOne')
// sum.value = store.state.sum
}
// bigSum = computed(() => {return sum*10})
return {
// sum,
addOne
}
},
computed:{
...mapState(['sum']),
...mapGetters(['bigSum'])
}
}
</script>
<style>
</style>
// store/index.js
......
const getters = {
bigSum(state){
return state.sum*10
}
}
......
export default createStore({
actions,
mutations,
state,
getters
})
你也可以通过让 getter 返回一个函数,来实现给 getter 传参。
下面的例子通过参数决定扩大的倍数。
// store/index.js
const getters = {
bigSum : (state) => (beishu) => {
return state.sum * beishu
}
}
<!-- Count.vue -->
<template>
<h1>{{bigSum(5)}}</h1>
</template>
Mutation
前面使用的求和案例中已经使用了Mutation
需要注意的是如果要用map,则不能在setup中使用来得到,Vue并不支持这样的操作,不过可以通过自己编写程序来实现。
传递参数
// store/index.js
const mutations = {
incrementOne(state, v){
state.sum += v
}
}
<!-- Count.vue -->
store.commit('incrementOne', 10)
使用常量替代 Mutation 事件类型
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne(1)">+1</button>
<h1>{{bigSum(5)}}</h1>
</template>
<script>
import { ref, computed } from 'vue';
import { useStore, mapState, mapGetters, mapMutations } from 'vuex' // 引入useStore 方法
export default {
name: 'Count',
setup(){
const store = useStore()
console.log(store)
return {
}
},
computed:{
...mapState(['sum']),
...mapGetters(['bigSum'])
},
methods:{
...mapMutations({
addOne:'SOME_MUTATION'
})
}
}
</script>
<style>
</style>
// store/index.js
import {createStore} from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const actions = {
}
const getters = {
bigSum : (state) => (beishu) => {
return state.sum * beishu
}
}
const mutations = {
[SOME_MUTATION](state, v){
state.sum += v
}
}
const state = {
sum: 0
}
export default createStore({
actions,
mutations,
state,
getters
})
// store/mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
一条重要的原则就是要记住 mutation 必须是同步函数。
你可以在组件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。
Action
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
下面是一个例子,等0.5s后再加。定时器无法直接在mutation中使用。
const actions = {
addWait(context, value){
setTimeout(() => {context.commit(SOME_MUTATION, value)}, 500)
}
}
<!-- Count.vue -->
<template>
<h1>当前求和为:{{sum}}</h1>
<button @click="addOne(1)">+1</button>
<button @click="addWait(2)">等一下再加</button>
<h1>{{bigSum(5)}}</h1>
</template>
<script>
import { ref, computed } from 'vue';
import { useStore, mapState, mapGetters, mapMutations, mapActions } from 'vuex' // 引入useStore 方法
export default {
name: 'Count',
setup(){
const store = useStore()
console.log(store)
return {
}
},
computed:{
...mapState(['sum']),
...mapGetters(['bigSum'])
},
methods:{
...mapMutations({
addOne:'SOME_MUTATION'
}),
...mapActions(['addWait'])
}
}
</script>
<style>
</style>
Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
一个简单的例子
// store/index.js
import {createStore} from 'vuex'
import dog from './dog'
import cat from './cat'
const state = {
person: '小明'
}
export default createStore({
state,
modules:{
cat,
dog
}
})
// store/dog.js
export default {
namespaced: true,
actions: {
},
getters: {
nicheng(state, getters, rootState){
let l = '亲爱的'+state.name
console.log('小狗的昵称:'+ l)
console.log(rootState.person)
return l
}
},
mutations: {
ageAdd(state){
state.age++
}
},
state:{
name:'小狗',
age:1,
}
}
// store/cat.js
export default {
namespaced: true,
actions: {
},
getters: {
nicheng(state, getters, rootState){
let l = '亲爱的'+state.name
console.log('小猫的昵称:'+ l)
console.log(rootState.person)
return l
}
},
mutations: {
ageAdd(state){
state.age++
}
},
state:{
name:'小猫',
age:10,
}
}
<!-- App.vue -->
<template>
<Cat></Cat>
<Dog></Dog>
</template>
<script>
import { } from 'vue'
import Dog from './components/Dog.vue'
import Cat from './components/Cat.vue'
import { useStore } from 'vuex' // 引入useStore 方法
export default {
name: 'App',
components: {
Dog,
Cat
},
setup(){
const store = useStore()
return{
}
}
}
</script>
<style></style>
<!-- Dog.vue -->
<template>
<div id="dog" >
<h1>名字:{{name}}</h1>
<h1>爱称:{{nicheng}}</h1>
<h1>年龄:{{age}}</h1>
<button @click="ageAdd">长大一岁</button>
<h1>小狗得到了小猫的信息:名字:{{catName}},年龄:{{catAge}}</h1>
</div>
</template>
<script>
import { reactive, computed } from 'vue';
import { mapGetters, mapState, useStore } from 'vuex' // 引入useStore 方法
export default {
name: 'Dog',
setup(props){
const store = useStore()
let name = computed(() => {return store.state.dog.name})
let age = computed(() => {return store.state.dog.age})
let nicheng = computed(() => {return store.getters['dog/nicheng']})
function ageAdd(){
store.commit('dog/ageAdd')
}
let catName = computed(() => {return store.state.cat.name})
let catAge = computed(() => {return store.state.cat.age})
return {
name,
age,
nicheng,
ageAdd,
catName,
catAge
}
},
}
</script>
<style>
#dog {
background-color: lightblue;
}
</style>
<!-- Cat.vue -->
<template>
<div id="cat" >
<h1>名字:{{name}}</h1>
<h1>爱称:{{nicheng}}</h1>
<h1>年龄:{{age}}</h1>
<button @click="ageAdd">长大一岁</button>
<h1>小猫得到了小狗的信息:名字:{{dogName}},年龄:{{dogAge}}</h1>
</div>
</template>
<script>
import { reactive } from 'vue';
import { mapGetters, mapMutations, mapState, useStore } from 'vuex' // 引入useStore 方法
export default {
name: 'Cat',
setup(props){
const store = useStore()
return {
}
},
computed:{
...mapState('cat', ['name', 'age']),
...mapGetters('cat', ['nicheng']),
// 获取Dog中的数据
...mapState('dog',{
dogName:'name',
dogAge:'age'
})
},
methods:{
...mapMutations('cat', ['ageAdd'])
}
}
</script>
<style>
#cat {
background-color: lightcoral;
}
</style>