一. Vuex 概述
1. 组件之间数据传递的方式
- 父向子传值:v-bind 属性绑定
- 子向父传值:v-on 事件绑定
- 兄弟组件之间共享数据:EventBus
上面这三种方案只适合小范围内的数据共享,如果是大范围的数据共享,这种方式就力不从心了。
2. Vuex 是什么
Vuexs 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
3. 使用 Vuex 统一管理状态的好处
- 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
- 能够高效地实现组件之间的数据共享,提高开发效率
- 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步
4. 什么样的数据适合存储到 Vuex 中
一般情况下,只有组件之间共享的数据,才有必要存储到 vuex 中,对于组件中的私有数据,依旧存储在组件自身的 data 中即可。
二. Vuex 基本使用
- 安装 vuex 依赖包
如果是可视化界面,添加如下vuex即可安装:
如果是命令行,执行如下命令即可安装vuex:
npm install vuex --save
- 导入 vuex 包
import Vuex from 'vuex'
Vue.use(Vuex)
- 创建 store 对象
const store = new Vuex.Store({
// state 中存放的就是全局共享的数据
state: { count: 0 }
})
- 将 store 对象挂载到 vue 实例中
new Vue({
el: '#app', // 指定要控制的区域
render: h => h(app), // 渲染根组件
router, // 挂载路由
// 将创建的共享数据对象,挂载到 Vue 实例中
// 所有的组件,就可以直接从 store 中获取全局的数据了
store
})
三. Vuex 核心概念
Vuex 的核心概念如下:
- State
- Getter
- Mutation 可变,突变,变异
- Action
为了使用方便,在使用Vuex之前我们先定义types对象:
// types对象
const types = {
SET_ADDRESS: 'SET_ADDRESS', //地址
ORDER_INFO: 'ORDER_INFO', //订单信息
ADDRESS_INFO: 'ADDRESS_INFO', //选中地址信息
REMARK_INFO: 'REMARK_INFO', //餐具信息 + 订单备注都存在这一个vuex中
};
1. State
State 提供唯一的公共数据源,所有共享的数据都要统一放到 State 中进行存储。State是个对象,里面存储着我们定义的属性。定义State的方式如下:
// state
const state = {
address: '',
orderInfo: null,
addressInfo: null,
remarkInfo: {
tableware: '',
remark: ''
}
};
this.$store.state.xxx
访问 State 中的数据通过如下方式:
this.$store.state.xxx
2. Getters
Getter 用于对 Store 中的数据进行加工处理形成新的数据,类似 Vue 的计算属性。Store 中数据发生变化,Getter 的数据也会跟着变化。Getter是个对象,里面定义获取 Store 中数据的方法,只有返回值。定义Getter的方式如下:
const getters = {
//不加工,直接返回
address: state => state.address,
orderInfo: state => state.orderInfo,
addressInfo: state => state.addressInfo,
//根据订单信息计算总价,所以只有getter方法在,没有state
totalPrice: state => {
let price = 0;
if (state.orderInfo) {
const selectFoods = state.orderInfo.selectFoods;
selectFoods.forEach(food => {
price += food.activity.fixed_price * food.count;
});
price += state.orderInfo.shopInfo.float_delivery_fee;
}
return price;
},
remarkInfo: state => state.remarkInfo
};
this.$store.getters.xxx
获取getters数据方式如下,一般我们会在使用的地方,将getters定义为计算属性。
this.$store.getters.xxx
3. Mutations
Mutation 用于变更 Store中 的数据,只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据,通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。Mutations也是个对象,里面定义了许多修改数据的方法,需要接收参数。定义Mutations方式如下:
// 定义mutations
const mutations = {
//通过types对象拿到方法名,后面参数,其中第一个是stage,第二个是传递的参数
[types.SET_ADDRESS](state, address) {
if (address) {
state.address = address;
} else {
state.address = null;
}
}
};
this.$store.commit('xxx')
触发Mutations通过如下方式:
//第一个参数是Mutations函数名,第二个参数是Mutations函数的参数
this.$store.commit(types.SET_ADDRESS, "杭州市")
4. Actions
如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutations,但是在 Action 中还是要通过触发Mutation 的方式(也就是提交commit)间接变更数据。Actions也是个对象,里面定义了许多修改数据的方法,需要接收参数。定义Action方式如下:
// actions
const actions = {
setAddress: ({ commit }, address) => {
setTimeout(() => {
// 触发mutations的方式间接变更数据
// 第一个参数是mutations函数名,第二个参数是mutations函数的参数
commit(types.SET_ADDRESS, address);
}, 1000)
}
};
这里有一个非常重要的参数context,context是一个和store实例均有相同方法和属性的context对象。所以我们可以从其中获取到commit方法来提交一个mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。但是为什么它不是store对象呢?这个等到我们讲Modules时再具体来说。
this.$store.dispatch('xxx')
触发Action通过如下方式:
this.$store.dispatch("setAddress",jsonData.regeocode.formattedAddress);
四. Vuex 案例
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
// types对象
// 设置types的目的是便于我们在vue调试工具中调试的时候看到名字
const types = {
SET_LOCATION: 'SET_LOCATION', //定位信息
SET_ADDRESS: 'SET_ADDRESS', //地址
ORDER_INFO: 'ORDER_INFO', //订单信息
ADDRESS_INFO: 'ADDRESS_INFO', //选中地址信息
REMARK_INFO: 'REMARK_INFO', //餐具信息 + 订单备注都存在这一个vuex中
};
// 定义state
const state = {
location: {},
address: '',
orderInfo: null,
addressInfo: null,
remarkInfo: {
tableware: '',
remark: ''
}
};
// 定义getters
// Getter 用于对 Store 中的数据进行加工处理形成新的数据,类似 Vue 的计算属性。 Store 中数据发生变化,Getter 的数据也会跟着变化。
const getters = {
//不加工,直接返回
location: state => state.location,
address: state => state.address,
orderInfo: state => state.orderInfo,
addressInfo: state => state.addressInfo,
//根据订单信息计算总价,所以只有getter方法在,没有state
totalPrice: state => {
let price = 0;
if (state.orderInfo) {
const selectFoods = state.orderInfo.selectFoods;
selectFoods.forEach(food => {
price += food.activity.fixed_price * food.count;
});
price += state.orderInfo.shopInfo.float_delivery_fee;
}
return price;
},
remarkInfo: state => state.remarkInfo
};
// 定义mutations
const mutations = {
[types.SET_LOCATION](state, location) {
if (location) {
state.location = location;
} else {
state.location = null;
}
},
[types.SET_ADDRESS](state, address) {
if (address) {
state.address = address;
} else {
state.address = '';
}
},
[types.ORDER_INFO](state, orderInfo) {
if (orderInfo) {
state.orderInfo = orderInfo;
} else {
state.orderInfo = null;
}
},
[types.ADDRESS_INFO](state, addressInfo) {
if (addressInfo) {
state.addressInfo = addressInfo;
} else {
state.addressInfo = null;
}
},
[types.REMARK_INFO](state, remarkInfo) {
if (remarkInfo) {
state.remarkInfo = remarkInfo;
} else {
state.remarkInfo = null;
}
}
};
// 定义actions
const actions = {
setLocation: ({ commit }, location) => {
// 触发mutations的方式间接变更数据
// 第一个参数是mutations函数名,第二个参数是mutations函数的参数
commit(types.SET_LOCATION, location);
},
setAddress: ({ commit }, address) => {
commit(types.SET_ADDRESS, address);
},
setOrderInfo: ({ commit }, orderInfo) => {
commit(types.ORDER_INFO, orderInfo);
},
setAddressInfo: ({ commit }, addressInfo) => {
commit(types.ADDRESS_INFO, addressInfo);
},
setRemarkInfo: ({ commit }, remarkInfo) => {
commit(types.REMARK_INFO, remarkInfo);
}
};
export default new Vuex.Store({
state,
getters,
mutations,
actions
});
一般我们通过this.$store.dispatch('xxx')
触发Actions的方式来设置数据到Vuex,如下:
this.$store.dispatch("setAddress",jsonData.regeocode.formattedAddress);
当使用Vuex中的数据的时候,一般都是将getters映射为组件的计算属性,如下:
computed: {
address() {
//定位信息
return this.$store.getters.address;
}
}
另外一个案例:Vuex案例:todolist,案例效果图如下:
网友评论