一、什么是vuex module,为什么要使用vuex模块化?
模块化,就是将vuex分为不同的模块,无论从项目上还是结构上,都容易维护,我们在平时写的vuex中,都是在一个文件中,写state、getters、mutations、actions。想象一下,如果我们的项目特别大,比如淘宝那么大,那么我们vuex中要维护的内容会特别多的时候,例如“购物车”需要用到vuex,“设置”需要用到vuex,“首页”也需要用到vuex,那么如果我们都写到一个文件中,就会出现代码相当的“臃肿”。这一个store文件最后好几万行代码。还怎么维护?
所以,我们vue官网就给出了办法,使用vuex模块化开发。
今天我们简单学习使用,学会后,你要查阅官网,深入学习,才能提高这个技术。
模块化有很多写法,今天按照我的习惯,简单的写一下,我们和以前一样,需要下载vuex,会得到一个store文件夹,内部我们有一个index跟文件。并且,我们需要自己创建一个modules文件夹,里边放入我们想要区分的js模块文件,你想分成多少个模块,就分成多少个,我目前写了俩个模块,一个是购物车car.js,一个是我的my.js,type.js先不用管。如图:
首先我们需要先将modules中的所有文件引入到index.js根文件中(以前我们是导出mutations等方法,现在这个文件中,我只引入了模块,所以只需要导出模块),如下(index.js):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import Vue from 'vue' ;
import Vuex from 'vuex' ;
// 引入两个模块文件
import car from './modules/car' ;
import my from './modules/my' ;
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
car,
my
}
});
|
然后我们就可以在每个模块当中,写入独立的state、mutations等等。这样我们在使用的时候,购物车就用car.js;我的就用my.js。用购物车car.js举例(其他文件同理),如下(car.js):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | const state = {
}
const getters = {
}
const mutations = {
}
const actions = {
}
export default {
namespaced: true ,
state,
getters,
mutations,
actions
}
|
这里就可以像以前一样写我们的vuex方法了。细心的同学会注意到,我们导出时,会多出一个namespaced:true,一般我们在模块使用时,都会加入这个属性。
命名空间:namesapced:true,当模块被注册后,它的所有getter、action及mutation都会自动根据模块注册的路径调整命名,也就是说,我们在调用这些方法时,需要加上这个文件的路径(比如我要访问这个文件中的state里边的某个属性:this.$store.state.car。后边这个car就是多了个car.js模块名,因为如果不加模块名,那我们会访问所有模块中的属性,那就乱了),所以我们要加上命名空间,相当于独立的区块去使用,模块和模块之间互不干扰。
和平时一样,我们跟个案例:
点击增加数值(car.js):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | const state = {
number: 100
}
const getters = {
}
const mutations = {
add(){
state.number ++;
}
}
const actions = {
}
export default {
namespaced: true ,
state,
getters,
mutations,
actions
}
|
我们重点说一下vue中怎么获取模块中的内容。我们可以和平常一样,直接用this.$store.state.car.number来获取到state中的number内容。我们今天说说在项目中最常使用的:辅助函数mapState、mapGetters、mapActions和mapMutations。
不一一举例,简单说两个mapState和mapActions,深入理解可去看官网。
我们在使用时,需要先引入:
1 | import { mapState, mapActions } from 'vuex' ;
|
这两个函数,前者写在计算属性computed中,后者写在方法methods中。
在写入时,需要用到展开符...,它可以将内容一一的展开。
举个例子:
1 2 3 4 | let a = [1, 2, 3];
let b = [4, 5, 6];
let c = [...a, ...b];
console.log(c); // [1, 2, 3, 4, 5, 6]
|
那我们获取一下state中的number:
1 2 3 4 5 6 7 8 9 10 11 | computed: {
...mapState({
a: state => state.car.number
})
},
methods: {
...mapMutations([ 'car/add' ]),
add(){
this [ 'car/add' ]() // 注意,这里this后没有点
}
},
|
展开mapState,定义一个a,然后返回state中的car模块下的number常量。展开mapMutations,返回是个数组,数组中是个字符串,返回car模块下的add方法,定义一个add,直接触发就可以。有人会问,触发mutations中的方法不是应该用commit吗,答案是我们用了mapMutations,它会将这个路径直接映射成commit方法,所以我们直接用就行,这也是与原来的区别。
我们定义的这个a,就是想要的数值,可以在标签中展示出来,add也直接使用。
1 2 | < h2 >{{a}}</ h2 >
< button @click='add'>点击增加</ button >
|
这样写出来,是好用的,但是看起来会有问题。想一下,car是个模块,我们现在只是举例而已,但是如果我们在开发中,这个模块下命名空间比较深入,还有其他模块,一层一层比较多,就会变成这个样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | computed: {
...mapState({
a: state => state.car.xx.xx.xx.number
// 如果下边还有很多,就要写很多重复的 car.xx.xx.xx,如:
b: state => state.car.xx.xx.xx.name
c: state => state.car.xx.xx.xx.key
})
},
methods: {
...mapMutations([ 'car/xx/xx/xx/add' ]),
add () {
this [ 'car/xx/xx/xx/add' ]()
}
}
|
这个层层的嵌套,那就要写很多重复的car/xx/xx/xx,所以我们可以,将这个模块当作字符串提取出来,换个写法,按照我们的举例:
1 2 3 4 5 6 7 8 | computed: {
...mapState( 'car' , {
a: state => state.number
})
},
methods: {
...mapMutations( 'car' , [ 'add' ]),
},
|
如上所示,我们可以将他作为参数,放到前面,这样所有绑定都会自动将该模块作为上下文,写出来也简单不少。当然我们还可以再简化一些。我们可以通过使用createNamesapcedHelpers创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数。
就是我们可以从vuex中引入createNamespacedHelpers,然后将刚才的字符串作为参数,传进来,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 这里引入createNamespacedHelpers
import { createNamespacedHelpers } from 'vuex' ;
// 定义mapState、mapMutations,并将car传入createNamespacedHelpers
const { mapState, mapMutations } = createNamespacedHelpers( 'car' );
computed: {
...mapState({
a: state => state.number
})
},
methods: {
...mapMutations([ 'add' ]),
},
|
这就是vuex模块化,写法都很多,看我们自己的习惯,当然了,我们在模块中,还可以使用常量替代Mutation事件类型。在多人开发时,我们知道mutations中放入了方法,如果有很多方法,多人协作时找起来会比较麻烦,那我们可以创建一个放入常量的文件(前文中我们创建的type.js文件),在里边我们可以定义常量,但注意的是,我们开发中习惯常量要大写,单词之间用下划线分开。并且,在模块中引入这个文件:
一、首先,我们创建一个js文件,我们前文图片中的type.js,在里边创建一个常量,开发时前后要一致,并加以标注:
1 2 3 4 5 | // 前后都要大写,一般前后名称一致,但是为了我们能够理解,本次我们写两个
// 开发中,我们应该这样写:export const ADD_NUMBER = 'ADD_NUMBER'
// 本次我们定义前后不一样的
export const ADD_NUMBER = 'AAA' // 点击增加数字
|
二、在car模块中引入type.js并使用引入进来的常量:// 按需引入常量import { ADD_NUMBER } from './type';
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | const state = {
number: 100
}
const getters = {
}
const mutations = {
// 使用常量命名,注意,这里[ADD_NUMBER]映射出来的名称,其实是AAA
// 我们写成固定的数字,也可以设置参数、灵活传参
// 第一个参数是state,第二个参数是传入参数payload
[ADD_NUMBER](state, payload){
state.number += payload;
}
}
const actions = {
}
export default {
namespaced: true ,
state,
getters,
mutations,
actions
}
|
三、vue页面,由于刚才我们用了payload参数,所以我们也需要传入参数,然后我们可以思考下,我们触发的名称应该写哪一个?
1 2 3 4 | methods: {
// 思考一下问号的地方,应该写 ADD_NUMBER还是AAA?
...mapMutations([ 'AAA' ]),
},
|
这个问题也就是我刚才故意在常量中,前后不一样的原因,由于我们前后都写一样,有些小白会不知道,这里定义的到底是前边的名称,还是后边字符串的名称。答案是AAA,也是ES6中对象的扩展写法。
最后的写法是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <h2>{{a}}</h2>
<button @click= 'aaa(2)' >点击增加</button>
computed: {
...mapState({
a: state => state.number
})
},
methods: {
// 思考一下问号的地方,应该写 ADD_NUMBER还是AAA?
// ...mapMutations(['AAA']),
// 我们除了可以写成数组,还可以用对象的写法
...mapMutations({
aaa: 'AAA'
})
// 你可以按照原始写法写,当然要去掉标签中的参数,参数改成下边传递。
// aaa(){
// this.$store.commit('car/AAA', 100);
// }
},
|
这就是modules模块化的开发写法,希望看完,你们会有所收获。
来源:https://yq.aliyun.com/articles/738863
|