浅谈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 相关文章推荐
jQuery 动画基础教程
Dec 25 Javascript
JQuery.ajax传递中文参数的解决方法 推荐
Mar 28 Javascript
js 通用javascript函数库整理
Aug 14 Javascript
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
Nov 06 Javascript
Javascript浅谈之引用类型
Dec 18 Javascript
jquery删除提示框弹出是否删除对话框
Jan 07 Javascript
IE下通过a实现location.href 获取referer的值
Sep 04 Javascript
Node.js异步I/O学习笔记
Nov 04 Javascript
javascript闭包概念简单解析(推荐)
Jun 03 Javascript
Vuex的actions属性的具体使用
Apr 14 Javascript
微信小程序实现点击空白隐藏的方法示例
Aug 13 Javascript
Vue实现星级评价效果实例详解
Dec 30 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+mysqli使用面向对象方式查询数据库实例
2015/01/29 PHP
php简单复制文件的方法
2016/05/09 PHP
JavaScript实现禁止后退的方法
2006/12/27 Javascript
jquery 图片缩放拖动的简单实例
2014/01/08 Javascript
jQuery学习笔记之 Ajax操作篇(三) - 过程处理
2014/06/23 Javascript
14款NodeJS Web框架推荐
2014/07/11 NodeJs
javascript框架设计读书笔记之数组的扩展与修复
2014/12/02 Javascript
jQuery获得document和window对象宽度和高度的方法
2015/03/25 Javascript
jquery专业的导航菜单特效代码分享
2015/08/29 Javascript
分享js粘帖屏幕截图到web页面插件screenshot-paste
2020/08/21 Javascript
详解Vue.js分发之作用域槽
2017/06/13 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
2017/11/22 Javascript
微信小程序scroll-view的滚动条设置实现
2020/03/02 Javascript
基于vue和bootstrap实现简单留言板功能
2020/05/30 Javascript
vue调用本地摄像头实现拍照功能
2020/08/14 Javascript
微信小程序实现弹幕墙(祝福墙)
2020/11/18 Javascript
python自动安装pip
2014/04/24 Python
使用Python编写类UNIX系统的命令行工具的教程
2015/04/15 Python
windows 10下安装搭建django1.10.3和Apache2.4的方法
2017/04/05 Python
深入理解Python单元测试unittest的使用示例
2017/11/18 Python
python版微信跳一跳游戏辅助
2018/01/11 Python
Python应用领域和就业形势分析总结
2019/05/14 Python
Windows 安装 Anaconda3+PyCharm的方法步骤
2019/06/13 Python
win7下 python3.6 安装opencv 和 opencv-contrib-python解决 cv2.xfeatures2d.SIFT_create() 的问题
2019/10/24 Python
Python项目跨域问题解决方案
2020/06/22 Python
python多线程semaphore实现线程数控制的示例
2020/08/10 Python
如何用Python 加密文件
2020/09/10 Python
详解CSS透明opacity和IE各版本透明度滤镜filter的最准确用法
2016/12/20 HTML / CSS
处理HTML5新标签的浏览器兼容版问题
2017/03/13 HTML / CSS
雅诗兰黛加拿大官网:Estee Lauder加拿大
2019/07/31 全球购物
澳大利亚窗帘商店:Curtain Wonderland
2019/12/01 全球购物
银行个人求职自荐信范文
2013/12/16 职场文书
三年大学自我鉴定
2014/01/16 职场文书
迎元旦广播稿
2014/02/22 职场文书
JavaScript原始值与包装对象的详细介绍
2021/05/11 Javascript
关于k8s环境部署mysql主从的问题
2022/03/13 MySQL