本文目录:
- 1.Vuex的定义
- 2.Vuex的使用流程
- 3.Vuex的核心概念
- 4.辅助函数mapState、mapGetters、mapMutations、mapActions
- 5.Module
- 6.实现Vuex的四个模块拆分
1.Vuex的定义
Vuex是什么?官方定义:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vue中跨组件的数据交互可以使用LocalStorage缓或者SessionStorage缓存,但是,这不是推荐的做法,也不方便,容易丢失数据或者是数据紊乱(因为没有及时清理与回收)
2.Vuex的使用流程
1 安装Vuex
npm install vuex --save
2 在src目录下,新建store文件夹,在store文件夹下新建index.js文件
3 在index.js文件中输入以下代码
import Vue from 'vue'
import Vuex from 'vuex'
// 让vuex作为vue的插件来使用
Vue.use(Vuex)
// 创建一个容器
let store = new Vuex.Store()
// 把这个store实例导出 方便在vue中注入
export default store
4 把store实例注入到vue中,在main.js中引入store
import Vue from 'vue'
import App from './App'
import router from './router'
import '@/assets/style/index.css'
//************************************************
import store from '@/store/index'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
//************************************************
store,
render: h => h(App)
})
接下来我们需要去使用vuex管理状态了,步骤
1、设置一个共享数据,在store/index.js里进行操作
// 创建一个容器
let store = new Vuex.Store({
state: {
goods_num: 0
}
})
2、在对应的组件中通过this.$store.state.goods_num就可以使用这个数据
3、组件中如果要修改.goods_num,则需要提交一个mutation,这个mutation类似于js中的事件,有事件类型和事件处理函数,我们在事件处理函数中去更改全局的goods_num
比如我们在组件通过通过定义有一个addNum事件去修改goods_num
以下是组件中的代码
4、在store里面去增加一个mutation, 在store/index.js里面操作
import Vue from 'vue'
import Vuex from 'vuex'
// 让vuex作为vue的插件来使用
Vue.use(Vuex)
// 创建一个容器
let store = new Vuex.Store({
state: {
goods_num: 0
},
mutations: {
//state就是上面的数据对象,num就是负责接收参数的形参
changeNum (state, num) {
state.goods_num += num
}
}
})
// 把这个store实例导出 方便在vue中注入
export default store
3.Vuex的核心概念
store: 每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)
state:包含所有应用级别状态的对象
Getter: 在组件内部获取store中状态的函数,可以认为是 store 的计算属性
Mutation: 唯一修改状态的事件回调函数
Action:Action 类似于 mutation,不同在于:1、Action 提交的是 mutation,而不是直接变更状态。2、Action 可以包含任意异步操作
Modules: 将store分割成不同的模块
Mutation
注意; 在Mutation中,是不能提交异步代码的,例如:
import Vue from 'vue'
import Vuex from 'vuex'
// 让vuex作为vue的插件来使用
Vue.use(Vuex)
// 创建一个容器
let store = new Vuex.Store({
state: {
goods_num: 0
},
mutations: {
changeNum (state, num) {
console.log(state)
setTimeout(() => {
state.goods_num += num
}, 2000)
}
}
})
// 把这个store实例导出 方便在vue中注入
export default store
Action
在mutation中提交异步代码,状态的改变是没办法追踪的,如果有异步代码,需要放到Action中去,等异步代码执行完成后再提交 store/index.js中的代码
import Vue from 'vue'
import Vuex from 'vuex'
// 让vuex作为vue的插件来使用
Vue.use(Vuex)
// 创建一个容器
let store = new Vuex.Store({
state: {
goods_num: 0
},
mutations: {
changeNum (state, num) {
state.goods_num += num
}
},
actions: {
changeNumAction (context, num) {
console.log(context)
setTimeout(() => {
//用comtext去调用commit,再去触发mutations
context.commit('changeNum', num)
}, 2000)
}
}
})
// 把这个store实例导出 方便在vue中注入
export default store
在对应的组件中通过dispatch去触发这个actions
export default {
data () {
return {
num: 12
}
},
components: {
},
methods: {
increase () {
this.num++
},
decrease () {
this.num--
},
addNum () {
// this.$store.commit('changeNum', this.num)
this.$store.dispatch('changeNumAction', this.num)
}
}
}
Getter
Getter可以认为是 store 的计算属性,可以对数据进行处理。为了掩饰效果,我们新建一个Count组件来说明
组件中的computed是局部的
getter可以认为是一个全局的计算属性
{{this.$store.state.count}}
在store中增加mutation函数和count变量,以下是部分代码
state: {
goods_num: 0,
count: 0
},
mutations: {
changeNum (state, num) {
state.goods_num += num
},
add (state) {
state.count++
}
}
这样我们就实现了vuex版的加法计数器,如果对count这个变量有一些逻辑判断怎么办呢?我们可以在组件内部使用computed来实现,如果这个逻辑是全局通用的,你可以把它放到Getter里面去,举例:
需求:当计数器加到10的时候就不能继续加了
在store中增加getters选项
getters: {
newCount (state) {
return state.count > 10 ? 10 : state.count
}
}
})
使用到时候,从store.getters对象中去获取
{{this.$store.getters.newCount}}
注意:如果要给getters里面的函数传参数,需要写成这样
getters: {
newCount (state) {
return state.count > 10 ? 10 : state.count
},
newCount2 (state) {
// 返回一个函数
return (num) => state.count > num ? num : state.count
}
}
调用的时候,这样调用
{{this.$store.getters.newCount2(5)}}
4.辅助函数mapState、mapGetters、mapMutations、mapActions
这几个辅助函数可以帮助我们简化一些写法
注意:在使用之前一定要先引入(在要使用的子组件中引入)
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
1.mapState,这个函数是computed的映射,可以把传入mapState的对象或者数组,转化成计算属性
mapState里面可以传入数组和对象,首先来看传入数组的写法
computed: {
...mapState(['num3', 'num4', 'num5'])
}
//这样的话,在子组件中就可以直接使用了
注意,这里传入的num3、num4、num5需要和state里面定义的状态同名
state: {
goods_num: 0,
count: 0,
num3: 9,
num4: 10,
num5: 11
}
这样写就可以直接去批量拿到state里面的数据,不用再去使用this.$store.state.num3 来获取值了,这就是辅助函数的作用,可以简化一些写法
有些时候,我们需要从state里面取值进行处理,例如这样:
computed: {
num3 () {
return this.$store.state.num3 > 10 ? 10 : 20
}
}
如果使用辅助函数,我们就需要以对象的形式传入了
computed: {
// num3 () {
// return this.$store.state.num3 > 10 ? 10 : 20
// }
...mapState({
num3: state => state.num3 > 10 ? 10 : 20
})
}
使用箭头函数可以简化代码,同时还可以给state里的状态重命名,例如:
computed: {
// num3 () {
// return this.$store.state.num3 > 10 ? 10 : 20
// }
...mapState({
num3: state => state.num3 > 10 ? 10 : 20,
num100: 'num4' //给num4 取一个别名 num100
})
}
如果你要使用this这个关键字,就不能用箭头函数,因此,可以简写成这样
computed: {
// num3 () {
// return this.$store.state.num3 > 10 ? 10 : 20
// }
...mapState({
num3: state => state.num3 > 10 ? 10 : 20,
num100: 'num4',
num6 (state) {
//需要取data里面的num99和state里面的num6相加,这个时候需要用到this
return this.num99 + state.num6
}
})
}
以上就是mapState的基本用法,mapMutations、mapGetters、mapActions的用法也一样, 简单举例:
//mapMutations的用法
methods: {
// increase () {
// this.$store.commit('add')
// }
...mapMutations({
increase: 'add'
}),
// decrease () {
// this.$store.dispatch('decreaseAction')
// },
//mapActions的用法
...mapActions({
decrease: 'decreaseAction'
})
},
//mapState的用法
computed: {
// num3 () {
// return this.$store.state.num3 > 10 ? 10 : 20
// }
...mapState({
num3: state => state.num3 > 10 ? 10 : 20,
num100: 'num4',
num6 (state) {
return this.num99 + state.num6
}
}),
//mapGetters的用法
...mapGetters({
num5: 'newCount'
})
}
5.Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块, 下面是我们的store/index.js文件,我们可以尝试将其拆分一个子模块出来
主要步骤
- 自定义一个对象(子模块)
- 将这个对象挂在store上
完整代码:
import Vue from 'vue'
import Vuex from 'vuex'
// 让vuex作为vue的插件来使用
Vue.use(Vuex)
// 1 自定义一个对象(子模块)
let countModule = {
state: {
count: 0,
num3: 9,
num4: 10,
num5: 11,
num6: 6
},
mutations: {
add (state) {
state.count++
},
decreaseMutation (state) {
state.count--
}
},
actions: {
decreaseAction (context) {
setTimeout(() => {
context.commit('decreaseMutation')
}, 1000)
}
},
getters: {
newCount (state, getters, rootState) {
return state.count > 10 ? 10 : state.count
},
newCount2 (state) {
return (num) => state.count > num ? num : state.count
}
}
}
// 创建一个容器
let store = new Vuex.Store({
state: {
goods_num: 0
},
mutations: {
changeCar (state, num) {
state.goods_num += num
}
},
actions: {
changeCarAction (context, num) {
console.log(context)
setTimeout(() => {
context.commit('changeCar', num)
}, 2000)
}
},
//2 将这个对象挂在store上
modules: {
countModule
}
})
// 把这个store实例导出 方便在vue中注入
export default store
//子组件使用的时候怎么用?
//{{this.$store.state.countModule. goods_num}}
//就是需要多加一个模块的名字
6.实现Vuex的四个模块拆分
创建四个分模块
const actions={}
export default actions
const getters = {}
export default getters
const mutations = {}
export default mutations
const state = {}
export default state
index.js中的代码
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import state from './state'
import mutations from './mutations'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
state,
actions,
mutations,
getters
})
export default store
上面这些都是创建vuex的基本代码
接下来在main.js中把store注册进去
import store from './store'
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
至此,vuex的模块拆分完成,接下来就可以正常使用vuex进行开发了。