浅谈Vue2.0父子组件间事件派发机制


Posted in Javascript onJanuary 08, 2018

从vue1.x过来的都知道,在vue2.0中,父子组件间事件通信的$dispatch和$broadcase被移除了。官方考虑是基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的过程中会变得越来越脆落。特别是在组件层级比较深的情况下。通过广播和事件分发的机制,就显得比较混乱了。

官方在废除的同时,也为我们提供了替换方案,包括实例化一个空的vue实例,使用$emit反应子组件上的状态变化

1.使用$emit触发事件

helloWorld.vue作为父组件,dialogConfigVisible变量控制子组件弹框显示或隐藏。

configBox.vue作为子组件,假设为封装的公告弹窗。

在父组件中 helloWorld.vue 中

< template/>

<config-box
   :visible="dialogConfigVisible"        
   @listenToConfig="changeConfigVisible"
 > </config-box>

script

data(){
  return {
   dialogConfigVisible:true
  }
 }
  methods: {
   changeConfigVisible(flag) {
     this.dialogConfigVisible = flag;
   }
  }

然后,在子组件 configBox.vue 中,主要在任意事件回调中,使用 $emit来触发自定义的 listenToConfig事件,后面还可以加上参数传给父组件。比如,在子组件弹窗上点击×关闭时,通知父组件 helloWorld.vue我要关闭了,主要方便父组件改变相应状态变量,并传入false到自定义的事件中。

script

methods:{
 dialogClose() {
  this.show = false;
  this.$emit("listenToConfig", false)
 }
}

在子?件中,主动触发listenToConfig事件,并传入参数 false, 告诉父组件 helloWorld.vue对话框要关闭了。这里就可以避免父组件中的状态未变化,再次刷新页面的时候对话框会自动出现。

2.实例化一个空的vue实例bus

这里实例化一个bus 空vue实例,主要为了统一管理子组件和父组件相互通信,通过bus 作为媒介,首先新建一个bus.js 文件,在里面新建一个对象,父组件为table.vue, 子组件为tableColumn.vue

// bus.js
 import Vue from "vue";
 export var bus = new Vue({
   data:{
    scrollY:false
   },
   methods:{
    updateScrollY(flag){
     this.scrollY = flag;
    }
   }
  })

然后分别引入:

// table.vue
 <script>
 import {bus} from "./bus"
  export default {
   created(){
    bus.$on('getData',(argsData)=>{
     // 这里获取子组件传来的参数
     console.log(argsData);
     })

   }
  }

 </script>
// tableColumn.vue
 <script>
  import {bus} from "./bus"
  export default{
   methods(){
    handleClick(){
     bus.$emit('getData',{data:"from tableColumn!"})
    }
   }
  }
 </script>

上面的父子组件中,父组件中利用bus注册监听事件getData,子组件中一旦有状态变化,就触发bus上对应的事件。

这种利用空实例的方式,相当于创建了一个事件中心,所以这种通信同样适用于非父子组件间的通信,

3.多级父子组件通信

有时,可能想要实现通信的两个组件不是直接的父子组件,而是祖父和孙子,或者是跨越了更多层级的父子组件

不可能由子组件一级一级的向上传递参数,来达到通信的目的,虽然现在我们理解的通信都是这样经过中转的。可以通过while等循环,不断向上遍历,直到找到目标父组件,就在对应的组件上触发事件。

下面就只element-ui实现的一个父子组件通信的mixins,对于组件同步有很大的作用。在element-ui 的优点概述中也特意提到这个组件通信

function broadcast(componentName, eventName, params) {

 // 向下遍历每个子节点,触发相应的向下广播的 事件
 this.$children.forEach(child => {
  var name = child.$options.componentName;

  if (name === componentName) {
   child.$emit.apply(child, [eventName].concat(params));
  } else {
   broadcast.apply(child, [componentName, eventName].concat([params]));
  }
 });
}
export default {
 methods: {
   // 向上遍历父节点,来获取指定父节点,通过$emit 在相应的 组件中触发 eventName 事件
  dispatch(componentName, eventName, params) {
   var parent = this.$parent || this.$root;
   var name = parent.$options.componentName;
   // 上面的componentName 需要在每个vue 实例中额外配置自定义属性 componentName,
   //可以简单替换成var name = parent.$options._componentTag;

   while (parent && (!name || name !== componentName)) {
    parent = parent.$parent;

    if (parent) {
     name = parent.$options.componentName;
    }
   }
   if (parent) {
    parent.$emit.apply(parent, [eventName].concat(params));
   }
  },
  broadcast(componentName, eventName, params) {
   broadcast.call(this, componentName, eventName, params);
  }
 }
};

首先定义两个嵌套的组件 f1.vue 和 c1.vue,实例是:

<f1>
  <c1></c1>
 </f1>

然后,分别定义两个父子组件:

c2.vue

<template>
   <section>
   <button type="button" name="button" @click="dispatchTest">点击一下,就可以</button>
  </section>
 </template>
<script type="text/javascript">
import Emitter from "../mixins/emitter";
export default {
name: "c2",
mixins: [Emitter],
componentName:'c2',
methods: {
 dispatchTest() {
  this.dispatch('f1', 'listenerToC1', false);
 }
}
}
</script>

 f1.vue

<template type="html">
 <div class="outBox-class">
  <slot>
  </slot>
 </div>
</template>

<script type="text/javascript">
import Emitter from "../mixins/emitter";
export default {
name: "f1",
mixins: [Emitter],
componentName: 'f1',
mounted() {
 this.$on("listenerToC1", (value) => {
   alert(value);
 })
}
}
</script>

这样,就可以在子组件中点击按钮,触发 listenerToC1事件,在父组件中监听到这个事件,

其实更$emit触发事件类似。不同之处在于,这里可以多级嵌套,不一定是直接的父子组件都可以触发到。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
中止javascript执行的方法
Feb 14 Javascript
一个获取第n个元素节点的js函数
Sep 02 Javascript
Javascript基础教程之break和continue语句
Jan 18 Javascript
jQuery使用append在html元素后同时添加多项内容的方法
Mar 26 Javascript
vue2.0 自定义日期时间过滤器
Jun 07 Javascript
通过示例彻底搞懂js闭包
Aug 10 Javascript
ionic App问题总结系列之ionic点击系统返回键退出App
Aug 19 Javascript
利用node实现一个批量重命名文件的函数
Dec 21 Javascript
React-router4路由监听的实现
Aug 07 Javascript
如何在Vue中抽离接口配置文件
Oct 31 Javascript
element跨分页操作选择详解
Jun 29 Javascript
Vue 事件的$event参数=事件的值案例
Jan 29 Vue.js
如何快速解决JS或Jquery ajax异步跨域的问题
Jan 08 #jQuery
jQuery+SpringMVC中的复选框选择与传值实例
Jan 08 #jQuery
浅谈SpringMVC中post checkbox 多选框value的值(隐藏域方式)
Jan 08 #Javascript
JQuery实现table中tr上移下移的示例(超简单)
Jan 08 #jQuery
使用 Vue 绑定单个或多个 Class 名的实例代码
Jan 08 #Javascript
(模仿京东用户注册)用JQuery实现简单表单验证,初学者必看
Jan 08 #jQuery
Angular 项目实现国际化的方法
Jan 08 #Javascript
You might like
php图片验证码代码
2008/03/27 PHP
Smarty的配置与高级缓存技术分享
2012/06/05 PHP
php文件夹的创建与删除方法
2015/01/24 PHP
PHP的Yii框架中移除组件所绑定的行为的方法
2016/03/18 PHP
php的常量和变量实例详解
2017/06/27 PHP
基于PHP实现的多元线性回归模拟曲线算法
2018/01/30 PHP
php正确输出json数据的实例讲解
2018/08/21 PHP
PHP通过调用新浪API生成t.cn格式短网址链接的方法详解
2019/02/20 PHP
Google Map API更新实现用户自定义标注坐标
2009/07/29 Javascript
Extjs改变树节点的勾选状态点击按钮将复选框去掉
2013/11/14 Javascript
纯js实现div内图片自适应大小(已测试,兼容火狐)
2014/06/16 Javascript
Javascript设计模式之观察者模式的多个实现版本实例
2015/03/03 Javascript
jQuery实现的左右移动焦点图效果
2016/01/14 Javascript
vue实现添加标签demo示例代码
2017/01/21 Javascript
详解jQuery设置内容和属性
2019/04/11 jQuery
如何利用vue+vue-router+elementUI实现简易通讯录
2019/05/13 Javascript
JS常用正则表达式超全集(密码强度校验,金额校验,IE版本,IPv4,IPv6校验)
2020/02/03 Javascript
Electron整合React使用搭建开发环境的步骤详解
2020/06/07 Javascript
vue 里面的 $forceUpdate() 强制实例重新渲染操作
2020/09/21 Javascript
[20:30]职业巡回赛回顾
2018/08/09 DOTA
[01:01]2020完美高校联赛(秋)西安落幕
2021/03/11 DOTA
python获取标准北京时间的方法
2015/03/24 Python
举例讲解Python编程中对线程锁的使用
2016/07/12 Python
python select.select模块通信全过程解析
2017/09/20 Python
python距离测量的方法
2018/03/06 Python
python如何使用unittest测试接口
2018/04/04 Python
python画折线图的程序
2018/07/26 Python
pycham查看程序执行的时间方法
2018/11/29 Python
对python numpy.array插入一行或一列的方法详解
2019/01/29 Python
python 使用openpyxl读取excel数据
2021/02/18 Python
自动一体化专业求职信
2014/03/15 职场文书
《鲁班和橹板》教学反思
2014/04/27 职场文书
试用期转正员工自我评价
2014/09/18 职场文书
2015元旦晚会主持词(开场白+结束语)
2014/12/14 职场文书
语文教师求职信范文
2015/03/20 职场文书
Flutter集成高德地图并添加自定义Maker的实践
2022/04/07 Java/Android