浅谈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 相关文章推荐
判断多个input type=file是否有已经选择好文件的代码
May 23 Javascript
JS在可编辑的div中的光标位置插入内容的方法
Nov 20 Javascript
详解JavaScript中jQuery和Ajax以及JSONP的联合使用
Aug 13 Javascript
JS组件系列之JS组件封装过程详解
Apr 28 Javascript
js实现京东秒杀倒计时功能
Jan 21 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
Feb 10 Javascript
JavaScript实现的弹出遮罩层特效经典示例【基于jQuery】
Jul 10 jQuery
bootstrap Table实现合并相同行
Jul 19 Javascript
vue实现表格过滤功能
Sep 27 Javascript
vue模块移动组件的实现示例
May 20 Javascript
原生js canvas实现鼠标跟随效果
Aug 02 Javascript
通过滑动翻页效果实现和移动端click事件问题
Jan 26 Javascript
如何快速解决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导入导出Excel代码
2015/07/07 PHP
wampserver改变默认网站目录的办法
2015/08/05 PHP
PHP+shell脚本操作Memcached和Apache Status的实例分享
2016/03/11 PHP
php 后端实现JWT认证方法示例
2018/09/04 PHP
javascript 简单抽屉效果的实现代码
2010/03/09 Javascript
ajax的hide隐藏问题解决方法
2012/12/11 Javascript
Jquery插件easyUi表单验证提交(示例代码)
2013/12/30 Javascript
JavaScript实现16进制颜色值转RGB的方法
2015/02/09 Javascript
JQuery实现可直接编辑的表格
2015/04/16 Javascript
jQuery zTree树插件简单使用教程
2017/01/10 Javascript
js+canvas实现动态吃豆人效果
2017/03/22 Javascript
ES6新特性五:Set与Map的数据结构实例分析
2017/04/21 Javascript
javascript实现非常简单的小数取整功能示例
2017/06/13 Javascript
jQuery选择器_动力节点Java学院整理
2017/07/05 jQuery
vue-cli 组件的导入与使用教程详解
2018/04/11 Javascript
JavaScript剩余操作符Rest Operator详解
2019/07/20 Javascript
[06:43]2018DOTA2国际邀请赛寻真——VGJ.Thunder
2018/08/11 DOTA
Python字符串详细介绍
2015/05/09 Python
python中abs&amp;map&amp;reduce简介
2018/02/20 Python
python将文本中的空格替换为换行的方法
2018/03/19 Python
基于python的多进程共享变量正确打开方式
2018/04/28 Python
Numpy数据类型转换astype,dtype的方法
2018/06/09 Python
python hashlib加密实现代码
2019/10/17 Python
python单向链表的基本实现与使用方法【定义、遍历、添加、删除、查找等】
2019/10/24 Python
在PyCharm中实现添加快捷模块
2020/02/12 Python
CSS3的颜色渐变效果的示例代码
2017/09/29 HTML / CSS
上班迟到检讨书
2014/01/10 职场文书
春季防火方案
2014/05/10 职场文书
国家奖学金获奖感言
2014/08/16 职场文书
运动会演讲稿200字
2014/08/25 职场文书
群众对十八届四中全会的期盼
2014/10/17 职场文书
预备党员2014年第四季度思想汇报范文
2014/10/25 职场文书
工作时间调整通知
2015/04/24 职场文书
名人传读书笔记
2015/06/26 职场文书
远程教育集中轮训基层干部培训班学习心得体会
2016/01/09 职场文书
变长双向rnn的正确使用姿势教学
2021/05/31 Python