基于Vue 2.x,对组件通信方式进行梳理,分为以下4类:
- 内置类
- 封装类
- 第三方类
- 其他
内置类
方式 | 说明 | 优点 | 缺点 | 栗子 |
---|---|---|---|---|
$ref / $parent / $children / $root | 避免在模板或计算属性中访问 $refs | 利于简单的父子通信 | 非父子,容易失控 | |
prop & $emit | 子组件通过props获取数据,$emit触发事件;父组件通过v-on绑定事件,监听子组件的触发事件 | 常用的父子通信 | 不利于跨级通信 | |
provide & inject(依赖 & 注入) | 父组件provide提供数据/方法给其所有子组件,子组件inject依赖注入数据/方法,可看作为大范围有效的 prop | 可跨级 | 1、非响应式,父值改变但子值仍原值;2、耦合性高,重构难度大,使用前考虑是否通用性高 | 【element】github.com/ElemeFE/ele… |
mixins / extends(混入 / 继承) | mixins:分发 Vue 组件中的可复用功能;extends:扩展单文件组件,类似mixins | 利于不同的逻辑分开到不同的 js 文件,mixins可多个 | 1、同名冲突;2、隐含的依赖关系,mixins和使用它的组件之间无层次关系 | 【element】github.com/ElemeFE/ele… |
$attrs | 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外) | 通过 v-bind="$attrs" 传入内部组件 | 【element】github.com/ElemeFE/ele… | |
$listeners | 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器 | 通过 v-on="$listeners" 传入内部组件 |
封装类
方式 | 说明 | 优点 | 缺点 | 栗子 |
---|---|---|---|---|
broadcast & dispatch(派发与广播) | 通过递归或遍历(上/下)来查找指定组件,接着在组件自身上$emit 与$on ,实现跨级通信 | 可跨级,简单可用 | 没有解决兄弟组件间的通信 | 【element】 github.com/ElemeFE/ele… |
vm.broadcast(componentName, eventName, params) // 在父组件调用,向下遍历子节点
vm.dispatch(componentName, eventName, params) // 在子组件调用,向上遍历父节点
vm.$on(eventName,callback) // 在父组件调用,监听对应事件(一般在mounted)
vm.$off(eventName,callback) // 在父组件调用,移除对应的事件监听(一般在beforeDestroy)
方式 | 说明 | 优点 | 缺点 | 栗子 |
---|---|---|---|---|
findComponents 系列方法 | 详见下文 | 找到指定组件的父子或兄弟组件 | 【view-design】 github.com/view-design… |
findComponentUpward(this,componentName) // 向上找到最近的指定组件
findComponentsUpward(this,componentName) // 向上找到所有的指定组件
findComponentDownward(this,componentName) // 向下找到最近的指定组件
findComponentsDownward(this,componentName) // 向下找到所有的指定组件
findBrothersComponents(this,componentName,exceptMe = true) // 找到指定组件的兄弟组件,exceptMe:是否把本身除外
第三方类
方式 | 说明 | 优点 | 缺点 | 栗子 |
---|---|---|---|---|
Vuex | 专为 Vue.js 应用程序开发的状态管理模式 | 1、解决了非父子组件的消息传递;2、减少了请求次数;3、属于 vue 生态一环,能够响应式地触发渲染页面更新;4、保证状态以一种可预测的方式发生变化 | 不适于简单的应用 |
state
存储状态变量
$sotre.state.xxx
/ $sotre.state.someModulesName.xxx
对应辅助函数:mapState
getter
可以认为是 store 的计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
$sotre.getters.xxx
/ $sotre.getters.xxx(params)
对应辅助函数:mapGetters
mutations
同步修改状态,与组件中的自定义事件类似
$store.commit('xxx', params)
对应辅助函数:mapMutations
actions
异步操作,不要直接去操作state,而是去操作mutation,类似于axios请求,可以都放在action中写
$store.dispath('xxx', params)
对应辅助函数:mapActions
modules
store的子模块,为了开发大型项目,方便状态管理而使用的
getters: {
checkedList: (state) => {
return state.dataList.filter(f => f.checked);
},
checkedListLength: (state, getters) => {
return getters.checkedList.length;
},
listLabelById: (state) => (id) => {
return state.dataList.find(f => f.id == id).label;
}
},
mutations: {
setUserToken(state, value) {
state.userToken = value;
},
setTmpObj(state, params) {
Vue.set(state.tmpMsg, params.key, params.value);
}
}
actions: {
toLogin({commit}, params) {
// 模拟异步请求
API.login(params, (res) => {
if (res) {
commit('setUserToken', res.data.token)
}
})
}
}
其他
方式 | 说明 | 优点 | 缺点 | 栗子 |
---|---|---|---|---|
eventBus / eventHub(中央事件总线) | 新增Vue对象,eventBus.$emit 触发事件;eventBus.$on 监听事件;eventBus.$off 销毁监听事件 | 可跨级 | 若只想监听一次事件触发,需要手动销毁监听,以免下次重复创建监听 | 详见下文 |
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
// 或 main.js
Vue.prototype.$EventBus = new Vue()
// 或 main.js
const eventBus = new Vue();
new Vue({
el: '#app',
data() {
return { bus: eventBus }
},
components: { App },
template: '<App/>'
})
this.$root.bus.$emit(eventName, […args])
this.$root.bus.$on(eventName, callback)
Last but not least
如有不妥,请多指教~