一、Vuex 概述
Vuex 是实现组件全局数据管理的一种机制,可以很方便的实现组件之间的数据共享。我们之前学习的组件之间的数据共享方式,如父子组件传值、EventBus 等,都只适用于小范围的数据共享。而 Vuex 可以实现整个项目范围的数据共享。
使用 Vuex 统一管理全局数据的优点:① 能够集中管理共享的数据,易于开发和后期维护。 ② 能够高效的实现组件之间的数据共享,提高开发效率。 ③ 存储在 vuex 中的数据是响应式的,能够实时保持数据与页面的同步。
二、Vuex 的安装
1、打开项目终端,输入 npm install vuex --D,下载vuex相关包。
2、在生成的 store/index.js 中,导入 vuex 包,并将其注入到 Vue 中。
3、创建 vuex 的 store 实例对象。
// 导入 vue
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// 将 vuex 注入到Vue中
Vue.use(Vuex)
// 创建实例对象
export default new Vuex.Store({
// state 中存放的就是全局共享的数据
state: {
count: 0
}
})
4、在项目的 main.js 中,将 store 实例对象挂载到 vue 实例上。
import Vue from 'vue'
import App from './App.vue'
// 导入对应实例对象
import store from './store'
new Vue({
// 将创建的 store对象,挂载到 Vue实例中
// 此时项目中的所有组件都可从该对象中获取数据
// store 是简写,全写为:store: store
store,
render: h => h(App)
}).$mount('#app')
三、Vuex的核心属性和使用方法
1、State
state 提供唯一的公共数据源,所有共享的数据都要统一放到 state中进行存储,state 中的数据不可直接进行修改。
// 创建实例对象
const store = new Vuex.Store({
// 存储所有共享数据
state: {
count: 1
}
})
组件中访问 state中存储的数据的两种方式:
① this.$store.state.全局数据名称
<!-- 在html中使用 -->
<h1>当前最新的count值为:{{$store.state.count}}</h1>
<!-- 在js中使用 -->
<script>
const num = this.$store.state.count
</script>
② 先按需导入vuex中的 mapState 函数,再通过该函数将需要的全局数据映射为当前组件的计算属性。
// 1. 从 vuex 中按需导入 mapState 函数
import { mapState } from 'vuex'
export default {
computed: {
// 2.通过 mapState 函数将需要的全局数据,映射为当前组件的计算属性使用
// 以数组的形式,可映射多个全局数据
...mapState(['count'])
}
}
2、Mutation
state 中的数据不可直接进行修改,只能通过 mutation 来变更 state 中的数据。虽然这会使操作变得繁琐,但是可以集中监控所有数据的变化。
// 创建实例对象
const store = new Vuex.Store({
// 存储所有共享数据
state: {
count: 1
},
// 定义 mutation
mutations: {
// 修改 state 中的数据
add(state) {
state.count++
},
// 可以传递参数
//第一个形参永远都是state也就是$state对象
//第二个形参是调用时传递的参数
addN(state, step) {
// 修改 state 中的数据
state.count += step
}
}
})
组件中触发 mutation的两种方式:
① this.$store.commit(‘mutation函数名’[,参数])
method: {
handle() {
// 通过 commit 函数来触发 mutation 中的函数
// 可以传递参数
this.$store.commit('addN',3)
}
}
② 先按需导入vuex中的 mapMutations 函数,再通过该函数将需要的 mutation 函数映射为当前组件的 methods 方法。
// 1. 从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex'
export default {
methods: {
// 2.通过 mapMutations 函数将需要的 mutation 函数,映射为当前组件的 methods 函数使用
// 以数组的形式 可映射多个 mutation 函数
...mapMutations(['add','addN'])
}
}
3、Action
Action 用来处理异步任务,在 mutation 中不能编写异步代码,会导致vue调试器的显示出错。但是Action 不能直接操作 state 中的数据,需要通过触发 mutation 来间接操作数据。
// 创建实例对象
const store = new Vuex.Store({
// 存储所有共享数据
state: {
count: 1
},
// 定义 mutation
mutations: {
// 可以传递参数
addN(state, step) {
// 修改 state 中的数据
state.count += step
}
},
// 定义 Action
actions: {
addNASync(context,step) {
// 异步操作
setTimeout(() => {
// 通过 commit 触发 mutation 来操作 state 中的数据
context.commit('addN',step)
})
}
}
})
组件中触发 Action 的两种方式:
① this.$storw.dispatch(‘action函数名’)
method: {
handle() {
// 通过 dispatch 函数来触发 action
// 可以传递参数
this.$store.dispatch('addNASync',5)
}
}
② 先按需导入vuex中的 mapActions 函数,再通过该函数将需要的 action 函数,映射为当前组件的 methods 方法。
// 1. 从 vuex 中按需导入 mapActions 函数
import { mapActions } from 'vuex'
export default {
methods: {
// 2.通过 mapActions 函数将需要的 action 函数,映射为当前组件的 methods 方法使用
// 以数组的形式 可映射多个 action 函数
...mapActions(['addNASync'])
}
}
4、Getter
Getter 用来对 state 中的数据进行加工处理并返回新的数据,类似于组件的计算属性。它不是对原有数据的修改,而是对其进行加工,并返回一个新的数据,state中的原数据不变。但是当 state 中的原数据发生改变时,Getter 的数据也会随之改变。
// 创建实例对象
const store = new Vuex.Store({
// 存储所有共享数据
state: {
count: 1
},
getters: {
// 参数 state 便是上面的 state
showNum(state) {
return '当前最新的数量是【' + state.count + '】'
}
}
})
组件中触发 Getter 的两种方式:
① this.$store.getters.getter函数名
<!-- 在html中使用 -->
<h1>{{$store.getters.showNum}}</h1>
<!-- 在js中使用 -->
<script>
const num = this.$store.getters.showNum
</script>
② 先按需导入vuex中的 mapGetters 函数,再通过该函数将需要的 getter 映射为当前数组的 computed。
// 1. 从 vuex 中按需导入 mapGetters 函数
import { mapGetters } from 'vuex'
export default {
computed: {
// 2.通过 mapGetters 函数将需要的 getter 映射为当前组件的 computed
// 以数组的形式 可映射多个 getter 函数
...mapGetters(['showNum'])
}
}
四、综合案例
1、store/index.js 文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
// 只有 mutations 中定义的函数,才有权利修改 state 中的数据
mutations: {
add(state) {
// 不要在 mutations 函数中,执行异步操作
// setTimeout(() => {
// state.count++
// }, 1000)
state.count++
},
addN(state, step) {
state.count += step
},
sub(state) {
state.count--
},
subN(state, step) {
state.count -= step
}
},
actions: {
addAsync(context) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的数据;
// 必须通过 context.commit() 触发某个 mutation 才行
context.commit('add')
}, 1000)
},
addNAsync(context, step) {
setTimeout(() => {
context.commit('addN', step)
}, 1000)
},
subAsync(context) {
setTimeout(() => {
context.commit('sub')
}, 1000)
},
subNAsync(context, step) {
setTimeout(() => {
context.commit('subN', step)
}, 1000)
}
},
getters: {
showNum(state) {
return '当前最新的数量是【' + state.count + '】'
}
}
})
2、Subtraction.Vue 组件
<template>
<div>
<!-- <h3>当前最新的count值为:{{count}}</h3> -->
<h3>{{showNum}}</h3>
<button @click="btnHandler1">-1</button>
<button @click="subN(3)">-N</button>
<button @click="subAsync">-1 Async</button>
<button @click="subNAsync(5)">-N Async</button>
</div>
</template>
<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
data() {
return {}
},
computed: {
...mapState(['count']),
...mapGetters(['showNum'])
},
methods: {
...mapMutations(['sub', 'subN']),
...mapActions(['subAsync', 'subNAsync']),
btnHandler1() {
this.sub()
}
}
}
</script>
3、Addition.vue 组件
<template>
<div>
<!-- <h3>当前最新的count值为:{{$store.state.count}}</h3> -->
<h3>{{$store.getters.showNum}}</h3>
<button @click="btnHandler1">+1</button>
<button @click="btnHandler2">+N</button>
<button @click="btnHandler3">+1 Async</button>
<button @click="btnHandler4">+N Async</button>
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {
btnHandler1() {
this.$store.commit('add')
},
btnHandler2() {
// commit 的作用,就是调用 某个 mutation 函数
this.$store.commit('addN', 3)
},
// 异步地让 count 自增 +1
btnHandler3() {
// 这里的 dispatch 函数,专门用来触发 action
this.$store.dispatch('addAsync')
},
btnHandler4() {
this.$store.dispatch('addNAsync', 5)
}
}
}
</script>