Vuex是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。多个组件共享状态,不同视图的行为需要变更同一状态时候则需要用到Vuex。
Vuex的五个概念
- state:定义共用的状态数据
- getters:根据state计算新的属性(类似于computed)
- actions:发起异步请求
- mutations:定义修改状态数据的方法
- modules:拆分模块
在项目中如何使用Vuex
1.下载安装vuex
npm install vuex -S
2.新建store目录,在store目录下新建index.js(目录和文件名随意)
在index.js中开始编写代码:
import Vue from 'vue'
import Vuex from 'vuex'
//插件,需要use
Vue.use(Vuex)
//定义共用的状态数据
const state = {
count: 0
}
export default new Vuex.Store({
state
})
在main.js中配置store
import Vue from 'vue'
import App from './App.vue'
import store from '../src/store/index' //+
Vue.config.productionTip = false
let vm = new Vue({
render: h => h(App),
store //+ 注入store,在任何组件中都可以通过$store对象操作状态
})
vm.$mount('#app')
在组件中使用state中的状态数据
<template>
<div id="app">
state.count:{{$store.state.count}}
</div>
</template>
结果:
在任意组件中获取state中的数据都可以用过this.$store.state来获取
3.修改state状态数据(mutations和actions)
通过dispatch分发事件
语法:this.$store.dispatch('事件名称', payload)
事件名称:actions中定义的函数名字
从文章的第一张图片可以看出,actions通过commit把事件提交给
mutations修改状态数据
具体语法:actions = {
函数({commit, state}[, payload]) {
xxx
commit('mutations事件名称'[,payload])
}
}
mutations = {
函数(state[,payload]) {
xxxx
}
}
payload是载荷,可选参数,传入的参数
为什么要有actions和mutations,只用mutations不行吗?
actio提交的是mutation,而不是直接变更状态
在mutation中只能执行同步代码,不能使用异步
而在action中可以使用任意的异步代码,不受约束
所以要存在actions和mutations
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
例子:
首先修改组件中的代码:
<template>
<div id="app">
state.count:{{$store.state.count}} <br />
{{$store.getters.odd_even}} <br />
<button @click="add">count+1</button>
<button @click="increment">count-1</button>
<button @click="delayAdd">count延迟1秒+1</button>
</div>
</template>
<script>
export default {
methods: {
add() {
this.$store.dispatch('add')
},
increment() {
this.$store.dispatch('increment')
},
delayAdd() {
this.$store.dispatch('delayAdd')
}
}
}
</script>
修改store/inde.js
import Vue from 'Vue'
import Vuex from 'Vuex'
//插件,需要use
Vue.use(Vuex)
const state = {
count: 0
}
//定义mutation
const mutations = {
ADD(state) {
//修改state中的数据
state.count++
},
INCREMENT(state) {
state.count--
}
}
//定义action
const actions = {
add({commit}) {
//提交mutation
commit('ADD')
},
increment({commit}) {
commit('INCREMENT')
},
delayAdd({commit}) {
setTimeout(() => {
commit('ADD')
},1000)
}
}
export default new Vuex.Store({
state,
actions,
mutations
})
4.派生状态getters
语法:
getters = {
getter名字(state) {
xxxx
return 返回的值
}
}
例子:页面显示state.count是奇数还是偶数
//在组件中添加:
{{$store.getters.odd_even}} <br />
//在store/index.js添加
const getters = {
odd_even: (state) => {
return state.count % 2 ===0 ? '偶数' : '奇数'
}
}
export default new Vuex.Store({
state,
getters, //+
actions,
mutations
})
整体效果:
5.mapState、mapActions、mapGetters辅助函数的使用
- mapState:当一个组件需要获取多个状态的时候,将这些属性声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性。
- mapActions:使用mapActions辅助函数将组件的methods映射为methods中的方法
- mapGetters:使用mapGetters辅助函数将store中的getter映射到局部计算属性
案例:
<template>
<div id="app">
state.count:{{$store.state.count}} <br />
{{$store.getters.odd_even}} <br />
<!-- 7.mapActions -->
<button @click="add">count+1</button>
<button @click="increment">count-1</button>
<button @click="delayAdd2">count延迟1秒+1</button>
<hr />
<!-- 3.mapState -->
<h3>count: {{count}}</h3>
<h3>selfCount: {{selfCount}}</h3>
<h3>countPlus: {{countPlus}}</h3>
<!-- 5.mapGetters -->
<h3>oddorEven: {{oddorEven}}</h3>
</div>
</template>
<script>
import {mapState, mapGetters, mapActions} from 'vuex' //1.引入辅助函数
export default {
data() {
return {
num: 10
}
},
computed:{
//2.使用mapState生成计算属性
//三种方法:
...mapState({
//使用函数返回state的属性
count:state => state.count,
//起别名,直接写state中的变量名,以字符串形式
selfCount: 'count',
//可以写表达式
countPlus() {
return this.count + this.num
}
}),
//4.mapGetters
/**
* computed: {
* ...mapGetters(['xxx']),
* ...mapGetters({新名字: 'xxx'})
* }
* 备注:xxx是getter的名字
*/
...mapGetters({
oddorEven: 'odd_even'
})
},
methods: {
//6.mapActions
/**
* ...mapActions(['xxx', 'xxx2'])
* ...mapActions({新名字: 'xxx'})
* 备注:xxx,xxx2是actions中定义的函数名称
*/
...mapActions(['add', 'increment']),
...mapActions({
delayAdd2: 'delayAdd'
})
}
}
</script>
6.模块化
在Vue中State使用的是单一状态树结构,应该所有的状态都放在State里面,如果项目比较复杂,state是一个人很大的对象,stroe对象也将会变得复杂难以管理。module模块化可以让每个模块拥有自己的state、mutations、actions、getters,让结构更为清晰,便于项目的管理。
export default new Vuex.Store({
state:{}, //公用的数据
getters:{},
mutations:{},
actions:{},
modules:{
模块名1:{
/*如果namespace为false(默认是false),state可以通过模块获得,
actions、getters、mutations依然是全局的,无法通过模块获得*/
namespace:true,
state:{},
getters:{},
mutations:{},
actions:{},
},
模块名2:{
namespace:true,
state:{},
getters:{},
mutations:{},
actions:{},
},
}
})
//通过this.$store.state.模块名.属性名获取模块的state
//通过this.$store.dispatch('模块名/action')修改state
//通过this.$store.getter['模块名/getter']获取getter
/**
* 模块中使用辅助函数
* ...mapState('模块名',{
* })
* ...mapGetters('模块名', {
* })
* ...mapActions('模块名',{
* })
*/
修改上面的案例,添加test模块:
- 修改store/index.js
import Vue from 'Vue'
import Vuex from 'Vuex'
//插件,需要use
Vue.use(Vuex)
const state = {
count: 0
}
const getters = {
odd_even: (state) => {
return state.count % 2 ===0 ? '偶数' : '奇数'
}
}
const mutations = {
ADD(state) {
state.count++
},
INCREMENT(state) {
state.count--
}
}
const actions = {
add({commit}) {
commit('ADD')
},
increment({commit}) {
commit('INCREMENT')
},
delayAdd({commit}) {
setTimeout(() => {
commit('ADD')
},1000)
}
}
export default new Vuex.Store({
state:{},
getters:{},
actions:{},
mutations:{},
modules:{
test:{//添加模块
namespaced: true,
state,
actions,
mutations,
getters
}
}
})
- 修改组件中的代码:
<template>
<div id="app">
state.count:{{$store.state.test.count}} <br /><!--变动-->
{{$store.getters['test/odd_even']}} <br /> <!--变动-->
<!-- 7.mapActions -->
<button @click="add">count+1</button>
<button @click="increment">count-1</button>
<button @click="delayAdd2">count延迟1秒+1</button>
<hr />
<!-- 3.mapState -->
<h3>count: {{count}}</h3>
<h3>selfCount: {{selfCount}}</h3>
<h3>countPlus: {{countPlus}}</h3>
<!-- 5.mapGetters -->
<h3>oddorEven: {{oddorEven}}</h3>
</div>
</template>
<script>
import {mapState, mapGetters, mapActions} from 'vuex' //1.引入辅助函数
export default {
data() {
return {
num: 10
}
},
computed:{
//2.使用mapState生成计算属性
//三种方法:
...mapState('test', {//变动,添加test模块
//使用函数返回state的属性
count:state => state.count,
//起别名,直接写state中的变量名,以字符串形式
selfCount: 'count',
//可以写表达式
countPlus() {
return this.count + this.num
}
}),
//4.mapGetters
/**
* computed: {
* ...mapGetters(['xxx']),
* ...mapGetters({新名字: 'xxx'})
* }
* 备注:xxx是getter的名字
*/
...mapGetters('test', {//变动,添加test模块
oddorEven: 'odd_even'
})
},
methods: {
//6.mapActions
/**
* ...mapActions(['xxx', 'xxx2'])
* ...mapActions({新名字: 'xxx'})
* 备注:xxx,xxx2是actions中定义的函数名称
*/
...mapActions('test', ['add', 'increment']),//变动,添加test模块
...mapActions('test', {//变动,添加test模块
delayAdd2: 'delayAdd'
})
}
}
</script>