1、vuex 是什么
实现数据共享
是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
概念:在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
不使用Vuex和使用Vuex:
使用Vuex统一管理状态的好处:
①能够在 vuex中集中管理共享的数据,易于开发和后期维护
②能够高效地实现组件之间的数据共享, 提高开发效率
③存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步
2、vuex 工作原理图
3、搭建vuex环境
npm i vuex
main.js
// 引入store
import store from './store'
new Vue({
el: '#app',
render: h => h(App),
store,
})
vuex 放在项目的 store文件夹中
store/index.js
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 应用Vuex插件
Vue.use(Vuex)
// 用于响应组件中的动作
const actions = {}
// 用于操作数据(state)
const mutations = {}
// 用于存储数据
const state = {}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
注意:需要在 store/index.js 应用Vuex,不然在main.js 中应用Vuex,但 import store from './store'
会先解析,会出错。
在文件中,import … from … 无论放任何位置,都会先被解析。
4、关于 actions、mutations、state
state
- vuex 管理的状态对象
- 它应该是唯一的
actions
- 值为一个对象,包含多个响应用户动作的回调函数
- 通过 commit( )来触发 mutation 中函数的调用, 间接更新 state
- 如何触发 actions 中的回调?
在组件中使用: $store.dispatch(‘对应的 action 回调名’) 触发
- 可以包含异步代码(定时器, ajax 等等)
mutations
- 值是一个对象,包含多个直接更新 state 的方法
- 谁能调用 mutations 中的方法?如何调用? 在 action 中使用:commit(‘对应的 mutations 方法名’) 触发
- mutations 中方法的特点:不能写异步代码、只能单纯的操作 state
案例:
Count.vue
<template>
<div>
<h1>当前数值为:{{ $store.state.sum }}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="myclick">+</button>
<button @click="Waitclick">1s后+</button>
data() {
return {
n: 1,
}
},
methods: {
myclick() {
// this.$store.dispatch('jia',this.n)
// 若无动作,可以直接commit
this.$store.commit('JIA',this.n)
}
Waitclick() {
this.$store.dispatch('waitjia',this.n)
}
}
store/index.js
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 应用Vuex插件
Vue.use(Vuex)
// 用于响应组件中的动作
const actions = {
// jia(context, value) {
// context.commit('JIA', value)
// }
waitjia(context, value) {
// console.log(context) {getters: {…}, state: {…}, rootGetters: {…}, dispatch: ƒ, commit: ƒ, …}
// 业务逻辑后commit
setTimeout(() => {
context.commit('JIA', value)
// 也可以不按标准,直接在actions中改state,但是开发者工具是连接mutations的,开发者工具将失效,所以不要这样写。
// context.state.sum += value
}, 1000)
}
}
// 用于操作数据(state)
const mutations = {
// mutations中函数一般用大写
JIA(state, value) {
state.sum += value
}
}
// 用于存储数据
const state = {
sum: 0
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
若actions 中要处理很多业务逻辑,
则可以用到 context 中的 dispatch(),相当于用很多服务员。
// 用于响应组件中的动作
const actions = {
waitjia(context, value) {
console.log('处理了一些事情')
context.dispatch('demo1', value)
},
demo1(context, value) {
console.log('我又哈哈哈处理了一些事情')
context.dispatch('demo2', value)
}
demo2(context, value) {
setTimeout(() => {
context.commit('JIA', value)
}, 1000)
}
}
为什么逻辑要写在actions中呢,因为如果很多组件都要这个逻辑,就会每个组件都要在methods中写逻辑,很麻烦,逻辑写在actions中,就可所有组件用,方便省事。
5、getters配置项
-
值为一个对象,包含多个用于返回数据的函数
-
如何使用?—— $store.getters.xxx
getters 用于将state中的数据进行加工
const getters = {
bigSum(state) {
return state.sum*10
}
}
使用:
<h1>数字放大10倍为:{{ $store.getters.bigSum }} </h1>
6、mapState与mapGetters
<h1>当前数值为:{{ $store.state.sum }} </h1>
<h1>数字放大10倍为:{{ $store.getters.bigSum }} </h1>
这样写很麻烦,总是有$store.state.
和 $store.getters.
所以这样:
<h1>当前数值为:{{ aa }} </h1>
<h1>学校:{{ bb }} </h1>
<h1>数字放大10倍为:{{ cc }} </h1>
computed: {
aa() {
return this.$store.state.sum
},
bb() {
return this.$store.state.school
},
cc() {
return this.$store.getters.bigSum
}
可是这样也很麻烦,需要在computed 中写很多$store.state.
和 $store.getters.
。
所以用到了mapState 与 mapGetters
Count.vue
import { mapState, mapGetters } from 'vuex'
computed: {
// 借助mapState生成计算属性(对象写法)
//...mapState({aa:'sum', bb: 'school'}),
// 借助mapState生成计算属性(数组写法)
...mapState(['sum','school']),
// 即对象写法中的...mapState({sum:'sum', school: 'school'}), 可以命名相同。
...mapGetters(['bigSum']),
}
x对象中放y对象,y前需要加 ...
就相当于将y展开放入x
7、mapActions与mapMutations
methods: {
myclick() {
this.$store.commit('JIA',this.n)
},
sheclick() {
this.$store.commit('JIAN',this.n)
}
Waitclick() {
this.$store.dispatch('waitjia',this.n)
}
}
有 this.$store.commit
若写很多也很麻烦,所以为了省略写this.$store.commit
用到了mapActions与mapMutations
import { mapActions, mapMutations } from 'vuex'
methods: {
// (对象写法)
...mapMutations({myclick: 'JIA', sheclick: 'JIAN'}),
// (数组写法)
// ...mapMutations(['JIA', 'JIAN']),
// mapActions同上
...mapActions({Waitclick: 'waitjia'}),
但是需要传值
<button @click = "myclick(n)">+</button>
<!-- (数组写法)-->
<!-- <button @click = "JIA(n)">+</button> -->
<button @click="Waitclick(n)">1s后+</button>
8、多组件共享数据
9、vuex模块化
看下面例子
index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 引入小仓库
import home from './home'
import detail from './detail'
export default new Vuex.Store({
modules: {
home,
detail,
}
})
detail.js
// detail 模块的小仓库
import {
reqGoodsInfo
} from "@/api"
// state:仓库存储数据的地方
const state = {
goodInfo: {},
}
// mutations:修改state的唯一手段
const mutations = {
GETGOODINFO(state, goodInfo) {
state.goodInfo = goodInfo
},
}
// actions:处理action,书写自己的业务逻辑、也可以处理异步
const actions = {
// 获取产品信息
async getGoodInfo({
commit
}, skuId) {
// 向服务器发请求
let result = await reqGoodsInfo(skuId)
if (result.code == 200) {
commit("GETGOODINFO", result.data)
}
}
}
// getters:计算属性,用于简化仓库数据,让组件获取仓库的数据更方便
const getters = {
categoryView(state) {
// 需要加上 || {},否则若没请求到数据,则会报错
return state.goodInfo.categoryView || {};
},
skuInfo(state) {
return state.goodInfo.skuInfo || {};
},
}
// 对外暴露
export default {
state,
mutations,
actions,
getters,
}
main.js
// 引入仓库
import store from "@/store"
Dedail/index.vue
......
......
import { mapGetters } from "vuex";
export default {
name: "Detail",
data() {
return {
skuNum: 1,
};
},
mounted() {
this.$store.dispatch("getGoodInfo", this.$route.params.skuid);
},
computed: {
...mapGetters(["categoryView", "skuInfo"]),