引子
组件之间共享数据的方式
- 父向子传值: 父组件
v-bind
数据绑定,子组件props
接收 - 子向父传值:
$emit
子组件绑定自定义事件,触发执行后,传给父组件,父组件需要用事件监听来接收参数 - 兄弟组件之间共享数据: EventBus
$on
接收数据的那个组件
$emit
发送数据的那个组件
Vuex是什么
Vuex
是实现组件全局状态(数据)管理的一种模式,可以方便的实现组件之间数据的共享。
使用Vuex统一管理状态的好处
能够在vuex中集中管理共享的数据,易于开发和后期维护能够高效地实现组件之间的数据共享,提高开发效率。
使用了vuex的项目结构
在store/index
中创建store实例,并且暴露出去,在main.js
中引入并挂载到VUE实例中。
vuex核心概念
State
State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
……
})
在组件中访问有2种方式
方式一:
<h1>当前最新的count{{ $store.state.count }}</h1>
方式二: 通过导入mapState函数把全局数据映射为当前组件的计算属性,注意不要忘记解构。
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['count']),
},
}
Mutation
Mutation用于变更Store中的数据。并且只有这个有权修改store的数据。在组件中只能通过mutation变更Store数据,不可以直接操作Store 中的数据。
通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
使用
// 这个形参state相当于与mutations平齐的state
mutations: {
add (state) {
state.count++
},
// mutations 传参
addN (state, num) {
state.count += num
}
},
在组件中触发有2种方式
方式一:
在函数中使用
this.$store.commit('add')
方式二:
通过导入mapMutations
函数把mutations里的函数映射为当前组件的methods方法,同样注意不要忘记解构。
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
methods: {
...mapMutations(['sub']),
// 除了这样写,还可以直接在@click="sub"
btn () {
this.sub()
}
}
对象风格提交
提交 mutation 的另一种方式是直接使用包含 type
属性的对象,此时,整个对象都作为额外的形参的实参(载荷)传给 mutation 函数
this.$store.commit({
type: 'add',// 必须包含type
number: 8
})
因此应该修改已有的mutation函数
mutations: {
add (state, num) {
state.count += num.number
}
}
Mutation需遵守Vue的响应规则,最好提前在store 中初始化好所有所需属性。当需要在对象上添加新属性时,可以:this.$state.obj = { ...this.$state.obj,newProp: 123 }
注意:mutations函数中不能执行异步操作
Action
Action用于处理异步任务。
如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。
定义action
// 形参context相当于mutations
actions: {
addAsync (context) {
setTimeout(() => {
context.commit('add')
}, 1000)
},
// 但是通常会简化,并未简化延时
adds({ commit }){
commit('add')
}
addNAsync (context, num) {
setTimeout(() => {
context.commit('addN', num)
}, 1000)
}
},
触发action
方式一:在函数中使用this.$store.dispatch('addAsync')
方式二: 导入mapActions
,并解构
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
methods: {
...mapActions(['subAsync'])
}
也支持以对象风格触发,如mutation一样需要type属性
Getter
Getter用于对 Store 中的数据进行加工处理形成新的数据。但是并没有修改原数据,起到一个包装作用。
Getter可以对Store中已有的数据加工处理之后形成新的数据,类似Vue的计算属性。Store中数据发生变化,Getter的数据也会跟着变化。
定义getter
// getters
getters: {
showNum (state) {
return 'now' + state.count
}
},
触发getter
方式一:
<h1>{{ $store.getters.showNum }}</h1>
方式二:
通过导入mapGetters
函数把全局数据映射为当前组件的计算属性,不要忘记解构。
import { mapGetters } from 'vuex'
export default {
computed: {
...mapState(['count']),
...mapGetters(['showNum'])
},
}
Module
vuex
允许把store
分割成不同的模块,每个模块拥有自己的 state、mutation、action、getter
,甚至是嵌套子模块
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
//上面那两个就可以另启一个文件暴露出来并在此文件导入
const store = new Vuex.Store({
modules: {
myModuleA: moduleA,
myModuleB: moduleB
}
})
//调用的话
this.$store.state.myModuleA // -> moduleA 的状态
this.$store.state.myModuleB // -> moduleB 的状态
在模块内部,mutation
和getter
的state是模块的局部状态(数据)对象
action和getter局部状态通过 context.state
暴露出来,根节点状态则为 context.rootState
actions: {
addRootSum ({ state, commit, rootState }) {
commit('add')
}
}
命名空间
一般模块内部的 action、mutation
和 getter
是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。
可以通过添加 namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名(进行嵌套调用)。
未完……