1、安装Vuex
命令行输入:npm i vuex@3
注意:默认安装的是Vuex 4版本,适用与Vue 3,而Vuex 3版本适用于Vue 2,所以安装的时候要注意指定安装版本号
2、创建store
目前有两种方式:
1)创建vuex文件夹,然后在文件夹里面创建store.js
2)创建store文件夹,然后在文件夹里面创建index.js
目前开发中,两种方式都比较常用,官方介绍的是第二种。
3、在js文件中,定义actions、mutations、state对象,创建Vuex实例对象,并配置参数
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//用于响应组件的动作
const actions = {}
//用于操作数据
const mutations = {}
//用于保存数据
const state = {}
export default new Vuex.Store({
actions,
mutations,
state
})
4、在入口文件中(main.js)中,引用store,并配置Vue实例参数
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
const vm = new Vue({
store,
render: h => h(App),
}).$mount('#app')
console.log(vm)
5、实际使用案例
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//用于响应组件的动作
const actions = {
addStaff(context,staff){
let name = staff.name
let salary = staff.salary
if(name.trim() == '' || name.length > 4){
// console.log('姓名不合法')
return 301
}
if(isNaN(+salary)){
// console.log('工资输入不合法')
return 401
}
context.commit('ADD_STAFF',staff)
return 200
}
}
//用于操作数据
const mutations = {
ADD_STAFF(state,staff){
state.persons.unshift(staff)
},
ADD_ITEM(state,item){
state.items.unshift(item)
// console.log(state.items)
}
}
//用于保存数据
const state = {
persons:[],
items:[]
}
export default new Vuex.Store({
actions,
mutations,
state
})
1)组件中读取vuex数据:$store.state.items
2)组件中修改vuex数据:$store.dispatch('actions中的方法名',数据)或者$store.commit('mutations中的方法名',数据)
备注:若没有网络请求或者其他业务逻辑,可以直接跳过actions,可以不写dispatch,直接编写commit
问题:
-
- 为什么业务逻辑不写在组件中,而是写在Vuex的actions方法中?
为了复用,比如在实际工作当中,我们要创建一个订单,这时候需要判断用户是否登录,商品库存是否满足购买需求等等,如果写在组件中,那么在多个需要创建订单的页面中,都要写判断逻辑,而且一旦需要修改逻辑,那么所有组件都要更改,而写在actions方法中,就不存在上述问题
-
- actions方法中,第一个参数上下文中,为什么不只包含commit,反而要包含dispatch等其他
如果只包含commit方法,那么就没办法拿到state中的数据进行使用,也没有办法调用其他的dispatch方法进行业务逻辑判断,在实际工作当中,经常会把业务逻辑单独封装,以实现公用
-
- 为什么不在actions方法中进行对state数据的操作?
因为如果在actions方法中进行对state数据的操作,Vuex开发工具监测不到
Vuex核心特性
1、getters的使用:
○概念:当state中的数据需要经过加工后在使用时,可以使用getters进行加工(类似于计算属性computed)。并不是强制要求必须使用getters,比如仅在单个组件中需要对数据加工,完全可以使用computed,但是当多个组件功能都使用加工后的数据时,可以采用getters加工复用。
○在js中追加getters配置,示例代码:
- 在js中追加getters配置,示例代码:
const getters = {
nums(){
return state.persons.length
},
total(){
return state.persons.reduce((sum,item) => sum + item.salary,0)
},
totalPay(){
return state.items.filter(item => item.type==0).reduce((sum,item) => sum + item.amount,0)
},
totalIncome(){
return state.items.filter(item => item.type==1).reduce((sum,item) => sum + item.amount,0)
}
}
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
-
- 组件中读取getters数据:$store.getters.totalPay
2、四个map方法的使用
1)mapState方法,用于帮助我们映射state中数据为计算属性
computed:{
//mapState的对象写法
...mapState({'list':'persons'}),
//等同于
list(){
return this.$store.state.persons
}
}
computed:{
//mapState的数组写法
...mapState(['persons']),
//等同于
persons(){
return this.$store.state.persons
}
}
2)mapGetters方法,用于帮助我们将getters中数据为计算属性
computed:{
//mapGetters的对象写法
...mapGetters({'income':'totalIncome'}),
//等同于
income(){
return this.$store.getters.totalIncome
}
}
computed:{
//mapGetters的数组写法
...mapState(['totalIncome']),
//等同于
totalIncome(){
return this.$store.getters.totalIncome
}
}
3)mapActions方法,用于帮助我们生成与actions对应的方法,即:包含$store.dispatch(xxx)的函数
methods:{
//原始写法
/* average(){
this.$store.dispatch('average')
} */
//使用mapActions对象写法
// ...mapActions({average:'average'})
//使用mapActions数组写法
...mapActions(['average'])
}
4)mapMutations方法,用于帮助我们生成与mutations对应的方法,即:包含$store.commit(xxx)的函数
methods:{
//原始写法
/* ADD_AVERAGE(){
this.$store.commit('ADD_AVERAGE')
} */
//使用mapMutations对象写法
// ...mapMutations({ADD_AVERAGE:'ADD_AVERAGE'})
//使用mapMutations数组写法
...mapMutations(['ADD_AVERAGE']),
}
3、模块化+命名空间
1)目的:让代码更好维护,让多种数据分类更加清晰
2)使用:
- 按照一定规则将数据分别定义在不同的js文件中,注意:namespaced属性要设置为true
export default {
namespaced:true,
actions:{
addStaff(context,staff){
let name = staff.name
let salary = staff.salary
if(name.trim() == '' || name.length > 4){
// console.log('姓名不合法')
return 301
}
if(isNaN(+salary)){
// console.log('工资输入不合法')
return 401
}
context.commit('ADD_STAFF',staff)
return 200
},
average(context){
let salary = (context.getters.total / context.getters.nums).toFixed(2)
// console.log(salary)
context.commit('AVERAGE',salary)
}
},
mutations:{
ADD_STAFF(state,staff){
state.persons.unshift(staff)
},
AVERAGE(state,salary){
state.wage = salary
},
ADD_AVERAGE(state){
state.wage = +state.wage + 100
}
},
state:{
persons:[],
wage:''
},
getters:{
nums(state){
return state.persons.length
},
total(state){
return state.persons.reduce((sum,item) => sum + item.salary,0)
},
}
}
-
-
- 在store.js文件中,引用定义好的文件,并通过modules属性进行加载
-
import Vue from 'vue'
import Vuex from 'vuex'
import persons from './persons'
import accounts from './accounts'
Vue.use(Vuex)
export default new Vuex.Store({
modules:{
personOption:persons,
accountOption:accounts
}
})
-
-
- 开启命名空间后,读取state数据
-
- 方式一:直接读取 $store.state.accountOption(命名空间名称).items
- 方式二:借助mapState读取 ...mapState('personOption',['persons','wage'])
- 开启命名空间后,读取getters数据
- 方式一:直接读取 $store.getters['accountOption(命名空间名称)/totalPay(getters方法名)']
- 方式二:借助mapGetters读取 ...mapGetters('personOption',['nums','total'])
- 开启命名空间后,组件中调用dispatch
- 方式一:直接调用 $store.dispatch('personOption/addStaff',obj)
- 方式二:借助mapActions调用 ...mapActions('personOption',['average'])
Element-ui:npm i element-ui -S
如何配置element-ui
import ElementUI from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(ElementUI, { locale })