浅谈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 多浏览器兼容总结(实战经验)
Oct 30 Javascript
js中的caller和callee属性介绍和例子
Jun 07 Javascript
JavaScript页面模板库handlebars的简单用法
Mar 02 Javascript
json传值以及ajax接收详解
May 24 Javascript
JavaScript 对象字面量讲解
Jun 06 Javascript
AngularJS 模型详细介绍及实例代码
Jul 27 Javascript
通过jsonp获取json数据实现AJAX跨域请求
Jan 22 Javascript
JS基于正则截取替换特定字符之间字符串操作示例
Feb 03 Javascript
Vue + better-scroll 实现移动端字母索引导航功能
May 07 Javascript
layer提示框添加多个按钮选择的实例
Sep 12 Javascript
关于layui 实现点击按钮添加一行(方法渲染创建的table)
Sep 29 Javascript
JS前端基于canvas给图片添加水印
Nov 11 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
微信access_token的获取开发示例
2015/04/16 PHP
php实现在服务器端调整图片大小的方法
2015/06/16 PHP
PHP实现C#山寨ArrayList的方法
2015/07/16 PHP
实例讲解如何在PHP的Yii框架中进行错误和异常处理
2016/03/17 PHP
php上传大文件设置方法
2016/04/14 PHP
PHP单例模式是什么 php实现单例模式的方法
2016/05/14 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
PHP实现普通hash分布式算法简单示例
2018/08/06 PHP
laravel异步监控定时调度器实例详解
2019/06/21 PHP
解决PHPstudy Apache无法启动的问题【亲测有效】
2020/10/30 PHP
对字符串进行HTML编码和解码的JavaScript函数
2010/02/01 Javascript
javascript动画浅析
2012/08/30 Javascript
页面只能打开一次Cooike如何实现
2012/12/04 Javascript
利用JavaScript检测CPU使用率自己写的
2014/03/22 Javascript
一个通过script自定义属性传递配置参数的方法
2014/09/15 Javascript
Javascript基础教程之数据类型 (数值 Number)
2015/01/18 Javascript
jQuery()方法的第二个参数详解
2015/04/29 Javascript
AngularJS实用开发技巧(推荐)
2016/07/13 Javascript
Angularjs修改密码的实例代码
2017/05/26 Javascript
vue与bootstrap实现简单用户信息添加删除功能
2019/02/15 Javascript
jQuery与原生JavaScript选择HTML元素集合用法对比分析
2019/11/26 jQuery
微信小程序自定义弹出层效果
2020/05/26 Javascript
TypeScript 引用资源文件后提示找不到的异常处理技巧
2020/07/15 Javascript
Vue 修改网站图标的方法
2020/12/31 Vue.js
浅谈python爬虫使用Selenium模拟浏览器行为
2018/02/23 Python
Numpy与Pytorch 矩阵操作方式
2019/12/27 Python
浅析python 动态库m.so.1.0错误问题
2020/05/09 Python
Python+Dlib+Opencv实现人脸采集并表情判别功能的代码
2020/07/01 Python
使用html5新特性轻松监听任何App自带返回键的示例
2018/03/13 HTML / CSS
中国最大的潮流商品购物网站:YOHO!BUY有货
2017/01/07 全球购物
Servlet面试题库
2015/07/18 面试题
《鸿门宴》教学反思
2014/04/22 职场文书
售后服务承诺书模板
2014/05/21 职场文书
2014迎接教师节演讲稿
2014/09/10 职场文书
搞笑的爱情检讨书
2014/10/01 职场文书
python3实现Dijkstra算法最短路径的实现
2021/05/12 Python