个别杠精会说vuex是历史的产物,在下实在不敢苟同。不予回复。
建议初学者一步一脚印,切莫装B,毕竟我们都是站在巨人肩膀上的一员
一、Vuex的五大属性
**简述:为了让初学者有个概念上的认知,以下介绍仅使用大白话进行阐述,**详情请查阅官网vuex.vuejs.org/zh/guide/
vuex 中最关键的是store对象,这是vuex的核心。可以说,vuex这个插件其实就是一个store对象,每个vue应用仅有一个store对象。
const store = new Vuex.Store({ state: {}, mutations: {}, actions: {}, modules: {} });
Vuex.Store可以理解为一个全局的存储对象,该对象中有五个重要的属性如下所示,它们各司其职,又可以可以互相配合利用。下面我就介绍下它们各自的作用。
1.State :
存放数据的数据源
定义:
const store = new Vuex.Store({
state: {
List:[1,2,3,4,5,6,7]
}
})
组件中使用:
<script>
export default {
computed: {
list() {
return this.$store.state.List.filter(item => item > 3); }
}
}
</script>
结果:
获取数据源中的List数组,并进行过滤,输出的结果为 [4,5,6,7]。
如果其它组件也需要这种过滤的数据怎么操作呢?也许你会copy这行代码,放到需要的组件中去。那么问题又来了,甲方爸爸变更需求将>3变更成>6怎么办?你是不是需要到各个组件中去依次修改,这么无疑加大了工作量。怎么解决这种问题呢,请继续往下看。
2.Getter :
从 store 中的 state 中派生出一些状态,例如对state中List进行过滤
定义:
const store = new Vuex.Store({
state: {
List:[1,2,3,4,5,6,7]
},
getters: {
getListMax: state => {
return state.List.filter(item => item > 3)
}
}
})
组件中使用:
<script>
export default {
computed: {
list() {
return this.$store.getters.getListMax
}
}
}
</script>
这样**(1)中到问题就解决了,如果需求变更只需要在getters中到getListMax做修改即可**
3.注:Getter依赖
getter 可以依赖其它已经定义好的 getter
定义:
const store = new Vuex.Store({
state: {
list: [1, 2, 3, 4, 5, 6, 7]
},
getters: {
getListMax: state => {
return state.List.filter(item => item > 3)
},
listCount: (state, getters) => {
return getters.getListMax.length;
}
}
})
组件中使用:
<script>
export default {
computed: {
list() {
return this.$store.getters.getListMax
},
listCount() {
return this.$store.getters.listCount
} }
}
</script>
输出的结果为:列表[4,5,6,7] 长度4
4.Mutation:
用来更改state中数据源的唯一方法;
Mutation 必须是同步函数:
加深理解可参考:
1.www.jianshu.com/p/d071e205b…
2.www.zhihu.com/question/48…
当然你非要写成异步也没人拦着你,但是国有国法,家有家规,在编程学习的道路上,还是要遵循正规军的步伐。
定义:
很多小伙伴会对官网中的 “每个 mutation 都有一个字符串的事件类型 (type) 和 一个 回调函数 (handler)这句话表示不理解”,请结合下方代码的注释进行理解。
const store = new Vuex.Store({
state: {
List: [1, 2, 3, 4, 5, 6, 7]
},
mutation:{
//事件类型 (type) :“changeList”
changeList(state,payload) { //回调函数(handler):就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数 state.List[0]=99+payload.num }
}
})
组件中使用:
向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):大多数情况下载荷是一个对象
<script>
export default {
created:{
this.startMu()
console.log(this.$store.state.List[0])
},
methods: {
startMu(){
this.$store.commit('changeList',{
num:1
})
}
}
}
</script>
调用的方式也可以写成
this.$store.commit({
type:'changeList',//type属性指向的即为mutation的方法名
num:1
})
输出结果: 100;
5.Action :
Action 提交的是 mutation,通过mutation改变state中的数据。
Action 可以包含任意异步操作
定义:
const store = new Vuex.Store({
state: {
List: [1, 2, 3, 4, 5, 6, 7]
},
mutation:{
changeList(state,payload) {
state.List[0]=99+payload.num
}
},
actions: {
changeListAsync (context) {
return new Promise((resolve, reject) => {
context.commit('changeList',{num:1})
}).catch(error => {
reject(error)
})
}
}})
组件中使用:
<script>
export default {
created:{
this.startAc() },
methods: {
startAc(){
this.$store.dispatch('changeListAsync')
}
}
}
</script>
结果跟(4)中的一样,
在实际场景的应用中仅靠mutations的同步操作是不满足实际需求的,vuex的acitons,就解决了这个问题,可以执行异步操作,是用来解决mutations只有同步无异步的问题
6.扩展运算符(...)结合辅助函数实现vuex属性映射
(1.)辅助函数:mapState、mapGetters、mapActions、mapMutations
**(2).**mapState为例,其余可自行百度,目的都是一样,减少代码的重复性,提高编写效率:
定义:
const store = new Vuex.Store({
state: {
a:1,
b:2,
c:3
}
})
组件中使用:
<template>
<div>{{this.a}}</div>
<div>{{this.b}}</div>
</template>
<script>
export default {
computed: {
...mapState(['a','b','c']), }
}
</script>
...mapState(['a','b','c']), 就相当于以下代码,明显提高了代码编写效率。
<template>
<div>{{this.a}}</div>
<div>{{this.b}}</div>
</template>
<script>
export default {
computed: {
a(){
return this.$store.state.a
},
b(){
return this.$store.state.b
}
....
}
}
</script>
注:前面的方法名和获取的属性名是一致的。
7.Module:
实际开发中假设只使用一个stroe,久而久之,sotre中的代码量就会变得非常臃肿。
为了解决这一问题,Vuex 允许我们将 store 分割成多个模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
官网的此类描述就已经是大白话了,vuex的这个属性也是最好理解的。
但是怎么优美的去配置这个属性呢?请继续往下阅读
二、动态配置vuex.store
1.在store目录下创建一个modules文件夹,里面存放分割的多个模块(module),如下图所示
2.在modules文件夹下创建一个user.js模块(module)
以用户登录为例:
用户通过前端页面提交用户名/密码等信息,提交给后台;获的后台返回的token,并将token存放到vuex中。
为了让初学者更容易理解,简化下user.js中的代码,如下所示:
import { login } from '@/api/user' //引用访问后台的login接口
const state = {
token: "",
}
const mutations = {
SET_TOKEN: (state, token) => {
state.token = token
}
}
const actions = {
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
commit('SET_TOKEN', data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
}
export default {
namespaced: true,//此处定义命名空间
state,
mutations,
actions
}
模块创建完毕,通过1中我们得知modules文件夹下有很多类似的模块,下面我们就将这些模块进行统一配置
3.配置vuex的modules
(1).打开store下的index.js,代码如下
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
//通过正则表达式获取modules文件夹下的所有js文件
const modulesFiles = require.context('./modules', true, /\.js$/)
//动态配置vuex.store的核心代码-start
//遍历模块文件,将所有的单个模块,汇总成符合vuex规范的modules.
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
//控制台打印
console.log("modulePath",modulePath) console.log("moduleName",moduleName)
console.log("value",value) return modules
}, {})
//动态配置vuex.store的核心代码-end
console.log("modules",modules) //控制台打印
//vues.store统一配置modules
const store = new Vuex.Store({
modules,
getters
})
export default store
控制台modules打印结果如下,动态配置成功
基础小知识
reduce定义、****reduce应用场景思考
4.通过namespaced属性,在组件中使用actions
在创建的user.js模块中我们声明了命名空间namespaced: true,这个属性使我们能在
项目的各个组件中调用,方式如下:
this.$store.dispatch('user/login', parm)
parm即为传递的参数
注:因为是模块化动态配置的store,避免模块件不同模块命名冲突的问题,故使用
namespaced:true,其中user/login中的user即为模块名字