💬 聊聊Vue2.x组件通信那些事

1,057 阅读1分钟

基于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

如有不妥,请多指教~