浅谈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 相关文章推荐
js屏蔽鼠标键盘(右键/Ctrl+N/Shift+F10/F11/F5刷新/退格键)
Jan 24 Javascript
jquery选择器原理介绍($()使用方法)
Mar 25 Javascript
使用 stylelint检查CSS_StyleLint
Apr 28 Javascript
jQuery实现发送验证码并60秒倒计时功能
Nov 25 Javascript
JavaScript基于DOM操作实现简单的数学运算功能示例
Jan 16 Javascript
Node.js 使用request模块下载文件的实例
Sep 05 Javascript
使用Javascript简单计算器
Nov 17 Javascript
Angular(5.2-&gt;6.1)升级小结
Dec 27 Javascript
小程序二次贝塞尔曲线实现购物车商品曲线飞入效果
Jan 07 Javascript
JS实现获取数组中最大值或最小值功能示例
Mar 02 Javascript
解决包含在label标签下的checkbox在ie8及以下版本点击事件无效果兼容的问题
Oct 27 Javascript
详解TS数字分隔符和更严格的类属性检查
May 06 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
全国FM电台频率大全 - 3 河北省
2020/03/11 无线电
PHP5新特性: 更加面向对象化的PHP
2006/11/18 PHP
snoopy PHP版的网络客户端提供本地下载
2008/04/15 PHP
php-perl哈希算法实现(times33哈希算法)
2013/12/30 PHP
PHP开发中常见的安全问题详解和解决方法(如Sql注入、CSRF、Xss、CC等)
2014/04/21 PHP
ThinkPHP在新浪SAE平台的部署实例
2014/10/31 PHP
初学JavaScript_03(ExtJs Grid的简单使用)
2008/10/02 Javascript
javascript appendChild,innerHTML,join性能比较代码
2009/08/29 Javascript
利用jquery操作select下拉列表框的代码
2010/06/04 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
JavaScript中使用ActiveXObject操作本地文件夹的方法
2014/03/28 Javascript
JavaScript获取某年某月的最后一天附截图
2014/06/23 Javascript
jQuery中[attribute*=value]选择器用法实例
2014/12/31 Javascript
js+css实现上下翻页相册代码分享
2015/08/18 Javascript
JS数组排序技巧汇总(冒泡、sort、快速、希尔等排序)
2015/11/24 Javascript
深入理解JS DOM事件机制
2016/08/06 Javascript
vue2.0结合Element实现select动态控制input禁用实例
2017/05/12 Javascript
vue动画之点击按钮往上渐渐显示出来的实例
2018/09/29 Javascript
Vue.extend 编程式插入组件的实现
2019/11/18 Javascript
[51:05]DOTA2上海特级锦标赛主赛事日 - 5 败者组决赛Liquid VS EG第一局
2016/03/06 DOTA
[02:42]完美大师赛主赛事淘汰赛第三日观众采访
2017/11/25 DOTA
使用python对文件中的数值进行累加的实例
2018/11/28 Python
tensorflow2.0保存和恢复模型3种方法
2020/02/03 Python
python GUI库图形界面开发之PyQt5控件数据拖曳Drag与Drop详细使用方法与实例
2020/02/27 Python
Python数据相关系数矩阵和热力图轻松实现教程
2020/06/16 Python
Python操作MySQL数据库的示例代码
2020/07/13 Python
python 生成器需注意的小问题
2020/09/29 Python
Hotels.com拉丁美洲:从豪华酒店到经济型酒店的预定优惠和折扣
2019/12/09 全球购物
新员工试用期自我鉴定
2014/04/17 职场文书
2014最新房贷收入证明范本
2014/09/12 职场文书
房产公证书样本
2015/01/23 职场文书
签字仪式主持词
2015/07/03 职场文书
2015年新教师个人工作总结
2015/10/14 职场文书
2016党员党课心得体会
2016/01/07 职场文书
导游词之鲁迅祖居
2019/10/17 职场文书
JavaScript实现栈结构详细过程
2021/12/06 Javascript