浅析vuex的构成
vuex 引入 State、Getter 的概念对状态进行定义;使用 Mutation 和 Action对状态进行变更;引入Module对状态进行模块化分割;引入插件对状态进行快照、记录、以及追踪等;提供了mapState、mapGetters、 mapActions、 mapMutations 辅助函数方便开发者在vm中处理store。具体构成关系如下:
浅析vuex的使用
我们只需要利用vue的use机制将 实例化后的store对象 注入vue实例即可!如下图:
Vue.use(Vuex); // 1. vue的插件机制,安装vuex
let store = new Vuex.Store({ // 2.实例化store,调用install方法
state,
getters,
modules,
mutations,
actions,
plugins
});
new Vue({ // 3.注入store, 挂载vue实例
store,
render: h=>h(app)
}).$mount('#app');
vuex的store是如何注入到组件中的?
要解答这个问题,我们先从vuex的使用表象上着手,从上面的介绍我们知道,使用vuex之前我们要对vuex进行安装!核心代码如下:
Vue.use(Vuex); // vue的插件机制,安装vuex插件
上面的代码得益于vue的插件机制,会在调用vuex的 install方法时,装载vuex! 所以我们直接关注 install方法的实现,其核心代码如下:
Vue.mixin({ beforeCreate: vuexInit });
可见,store注入 vue的实例组件的方式,是通过vue的 mixin机制,借助vue组件的生命周期 钩子 beforeCreate 完成的。
即 每个vue组件实例化过程中,会在 beforeCreate 钩子前调用 vuexInit 方法。下面,我们将焦点聚焦在 vuexInit 函数。 下面为 vuexInit 的核心代码!
this.$store = typeof options.store === 'function'
? options.store()
: options.store
该代码的核心问题是this的指向,得益于mixin机制,this将指向 vue组件实例!最终,我们可以再 vue组件实例上获得vuex 的store 对象的引用 $store!图示如下:
vuex利用了vue的mixin机制,混合 beforeCreate 钩子 将store注入至vue组件实例上,并注册了 vuex store的引用属性 $store!
vuex的state 和 getter 是如何映射到 各个组件实例中自动更新的?
问题剖析
该问题的核心问题是当store中的 state 和 getter 方式变更时,vuex如何保证各个组件实例中的数据自动更新,并update 组件!简言之,某一组件store更新时,如何通知其他组件进行数据更新,和UI更新!通过简单分析可知,问题的根本就是组件通信的问题。
浅谈组件通信
从分析可知,要解答本篇疑问,我们需要从 vue组件通信谈起! 在使用vue的过程中,需要频繁的进行组件间通信!通信的主体之间的关系可以是 父子组件,也可以是 类似 兄弟组件 或者是 无关组件 等非父子组件。 总的来说 有如下几种方式:
- 通过props向子组件传递数据:父 -> 子
- 通过事件向父组件发送消息:子 -> 父,使用$emit发送事件
- 父链 和 子索引:
this.$parent与this.$children - 依赖注入:
provide和inject - 子组件引用:
ref与$refs - 特性绑定
:v-bind="$attrs"和v-on="$listeners" event bus- 利用全局变量、
storage、cookie、query、hash等传递数据: 非vue特性,不做赘述。 - 全局事件广播
主要介绍第7种,event bus。
其核心设计思想是引入中央通信桥梁——中央事件总线,使各个组件只与其进行通信,达到数据同步的通信目的!如下图 组件A数据变更,通知中央事件总线,其他组件监听并接收变更的数据。
下面代码展示了在vue中使用 中央事件总线 进行组件通信:
let bus = new Vue({
methods: {
emit (event, ...args) {
this.$emit(event, ...args);
},
on (event, callback) {
this.$on(event, callback);
}
}
});
//component A
bus.emit('updateData', data); // 发送数据给 bus。
//component B
bus.on('updateData', data => {
// 接收 updateData事件 发送的数据信息。
})
vue的中央事件总线的实现 简单讲就是新建了一个vue对象,借助vue对象的特性(emit on) 作为其他组件的通信桥梁,实现组件间的通信 以及数据共享!
vuex的state是借助vue的响应式data实现的。设计思想与vue中央事件总线如出一辙。
getter的实现借助了vue的computed的特性而实现。