1.Vuex的基本使用
1.安装vuex依赖包:
npm install vuex --save
2.导入vuex包
import Vuex from 'vuex'
Vue.use(Vuex)
3.创建store对象
const store = new Vuex.Store({
// state中存放的就是全局共享的数据
state: {count: 0}
})
- 将store挂载到vue实例中
new Vue({
el: '#app',
render: h => h(app),
router,
// 将创建的共享数据对象,挂载到Vue实例中
// 所有的组件,就可以直接从store中获取全局的数据了
store
})
2、Vuex的核心概念
2.1 State
在Vuex中,State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储,这里的Store相当于一个用于存储数据的公共容器。
const store = new Vue.Store({
state: {
count: 0
}
...
})
组件访问State中数据的第一种方式
this.$store.state.全局数据名称
过去是在html元素组件之间调用,则可以省略this,即:
<span>{{$store.state.全局数据名称}}</span>
组件访问State中数据的第二种方式
通过mapState辅助函数方式,实现组件访问State中数据的第二种方式
// 1. 从vuex中按需导入mapState函数
import { mapState } from 'vuex'
通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前的computed计算属性:
// 2. 将全局数据映射为当前组件的计算属性
computed: {
// ...表示展开映射,意思就是将全局属性映射为当前组件的计算属性
...mapState(['count'])
}
直接在调用获取组件属性
<span>{{count}}</span>
2.2 Mutation
Vuex中的Mutation是用于变更Store中的数据。
在Vuex中,只能通过mutation变更Store数据,不可以直接操作Store中的数据。虽然通过mutation的方式来操作数据,虽然繁琐了一点,但是却可以集中监控所有数据的变化。 例如让全局数据自增加1,则可以通过如下的方式在Mutation中定义
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
//变更状态
state.count++;
}
}
})
定义过mutation之后,下面介绍一下Vuex的触发方式
触发mutation方式一
通过$store.commit()函数来触发mutation。
methods: {
handle1 () {
// 触发mutations的第一种方式
this.$store.commit('add')
}
}
接着就可以通过@click方法来调用handle1,从而来触发mutation函数。
另外,可以在触发mutation函数时,传入参数
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
//变更状态
state.count++;
},
addN(state, n) {
state.count += n;
}
}
})
然后定义handler2
methods: {
handler2: {
this.$store.commit('addN', 5);
}
}
触发mutation方式二
通过导入mapMutations辅助函数来触发mutations。
// 1. 从vuex中按需导入mapMutations函数
import { mapMutations } from 'vuex'
...
// 2. 将制定的mutations函数映射为当前组件的methods函数
methods: {
// 将add和addN方法映射为methods中的函数,拱当前组件使用。
...mapMutations({'add', 'addN'}),
handleAdd() {
this.add();
},
handleAddN(n) {
this.addN(n);
}
// 或者直接在标签元素中直接@click=add()
}
对于mutations来说,只能够实现同步操作,不可以执行异步操作的。
2.3 Action
Action类似于mutation,不同之处在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
结论就是,如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。 如何定义Actions呢?
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
//变更状态
state.count++;
},
addN(state, n) {
state.count += n;
}
},
actions: {
// 通过context去调用mutation
addAsync(context) {
setTimeout(() => {
context.commit('add'
}, 1000)
},
// 调用Actions是也可以传入参数
addNAsync(context, n) {
setTimeout(() => {
context.commit('addN', n);
}, 1000);
}
}
})
需要注意的是只有通过mutation中定义的函数,才有权利去修改state中的数据,因此actions最终还是要调用mutation。
触发Actions的第二种方式 可以通过mapActions辅助函数的方式来触发Actions。
// 1. 从vuex中按需导入mapActions函数
import { mapActions } from 'vuex'
...
// 2. 将指定的actions函数,映射为当前组件的methos函数
methods: {
...mapActions(['addAsync', 'addNAsync'),
handleAddAsync() {
this.addAsync();
},
handleAddNAsync(n) {
this.addNAsync(n);
}
}
2.4 Getter
Getter的数据是基于Store中的数据的,所以当Store中数据发生变化时,Getter中的数据也会随之变化。
定义Getter
例如state中存有todos计划项,其对象有一个done状态表示完成与否。
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
// 这里通过getters定义的doneTodos方法来过滤已完成的todo项
doneTodos: state => {
return state.todos.filter(todo => todo.done);
},
// 这里还可以通过传入getters对象来获取其他方法
doneTodosCount: (state, getters) => {
return getters.doneTools.length;
},
// 传入参数
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id == id);
}
}
})
触发Getter定义函数的第一种方法
通过mapGetters来触发Getter中定义的函数
// 1. 导入mapGetters辅助函数
import { mapGetters } from 'vuex'
...
// 2. 将制定的Getters函数映射为当前组件的函数
methods: {
...mapGetters(['doneTodos', 'doneTodosCount']),
handleDoneTodos() {
this.doneTodos();
}
}
触发Getter定义函数的第二种方法
通过mapGetters来触发Getter中定义的函数
// 1. 导入mapGetters辅助函数
import { mapGetters } from 'vuex'
...
// 2. 将制定的Getters函数映射为当前组件的函数
methods: {
...mapGetters(['doneTodos', 'doneTodosCount']),
handleDoneTodos() {
this.doneTodos();
}
}
2.5 Module
Vuex提供了一个Module模块来分隔Store。通过对Vuex中的Store分隔,分隔成一个一个的Module模块,每个Module模块都拥有自己的state、mutation、actions和getters。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
对于模块中的mutations和getters,传入的第一个参数规定为state,而actions则依旧是context参数。如下:
const moduleA = {
state: {
count: 0
},
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
},
actions: {
// context对象其实包含了 state、commit、rootState。
incrementIfOddRootsum (context) {
if ((context.state.count + context.rootState.count) % 2 === 1) {
// 调用mutations
commit('increment')
}
}
}
}
在module中通过mapState、mapGetters、mapActions和mapMutations等辅助函数来绑定要触发的函数
第一种方式
methods: {
...mapActions([
'some/nested/module/foo',
'some/nested/module/bar'
])
}
在vuex中,可以为导入的state、getters、actions以及mutations命名别名,,这样可以方便调用
methods: {
...mapActions([
'foo': 'some/nested/module/foo',
'bar': 'some/nested/module/bar'
])
}
第二种方式
对于这种情况,你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为:
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
第三种方式
可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')
export default {
methods: {
// 在 `some/nested/module` 中查找
...mapActions([
'foo',
'bar'
])
}
}
总结
- Vuex主要用于管理Vue组件中共享的数据。
- Vuex中有state、mutation、action、getter等核心概念。
- 获取state可以通过this.$store.state.xx或者是通过定义mapState来获取。
- 修改state中的变量需要通过mutation函数实现,而mutation的触发由两种方式,一种是通过this.$store.commit()函数,另外一种就是通过mapMutations来实现。
- mutation只能用于修改数据,而Actions可以实现异步操作。
- 通过Actions的异步操作+mutation的修改数据,可以实现异步修改数据。调用Actions有两种方式,第一种是通过this.$store.dispatch来调用,另外一种方式是通过mapActions来调用。
- Getters函数用于对Store中数据进行加工,不会修改原本Store中的数据;Getters中的数据会受Store中数据进行影响。