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

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

1.使用$emit触发事件

helloWorld.vue作为父组件,dialogConfigVisible变量控制子组件弹框显示或隐藏。
configBox.vue作为子组件,假设为封装的公告弹窗。

在父组件中 helloWorld.vue 中

< template/>


&lt;config-box
:visible="dialogConfigVisible"
@listenToConfig="changeConfigVisible"
&gt; &lt;/config-box&gt;

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
&lt;script&gt;
import {bus} from "./bus"
export default {
created(){
bus.$on('getData',(argsData)=&gt;{
// 这里获取子组件传来的参数
console.log(argsData);
}) }
} &lt;/script&gt; // tableColumn.vue
&lt;script&gt;
import {bus} from "./bus"
export default{
methods(){
handleClick(){
bus.$emit('getData',{data:"from tableColumn!"})
}
}
}
&lt;/script&gt;

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

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

3.多级父子组件通信

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

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

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


function broadcast(componentName, eventName, params) { // 向下遍历每个子节点,触发相应的向下广播的 事件
this.$children.forEach(child =&gt; {
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 &amp;&amp; (!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,实例是:


&lt;f1&gt;
&lt;c1&gt;&lt;/c1&gt;
&lt;/f1&gt;

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


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

f1.vue &lt;template type="html"&gt;
&lt;div class="outBox-class"&gt;
&lt;slot&gt;
&lt;/slot&gt;
&lt;/div&gt;
&lt;/template&gt; &lt;script type="text/javascript"&gt;
import Emitter from "../mixins/emitter";
export default {
name: "f1",
mixins: [Emitter],
componentName: 'f1',
mounted() {
this.$on("listenerToC1", (value) =&gt; {
alert(value);
})
}
}
&lt;/script&gt;

这样,就可以在子组件中点击按钮,触发 listenerToC1事件,在父组件中监听到这个事件,
其实更$emit触发事件类似。不同之处在于,这里可以多级嵌套,不一定是直接的父子组件都可以触发到。

4 .sync 修饰符

在Vue1.x中,利用prop进行"双向绑定",实现父子组件通信,都会用到.sync修饰符,可以将子组件中对应的prop值变化同步到父组件中。但是,这样就破坏了单向数据流,在2.0版本中被移除了,在2.3.0版本中又以一种语法糖的形式加了进来。
可以看下文档上给出的实例


&lt;comp :foo.sync=“bar”&gt;&lt;/comp&gt;

被扩展为


&lt;comp :foo="bar" @update:foo= "val =&gt;bar=val"&gt;&lt;/comp&gt;

其实跟本文中第一种方法基本一致,更加简化了。

同样helloWorld.vue作为父组件, configBox.vue作为子组件,


&lt;config-box
:visible.sync="dialogConfigVisible"
&gt; &lt;/config-box&gt;

然后在子组件中,显式的触发更新事件:


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

这样visible 的变化就能同步到父组件中了。

原文地址:https://segmentfault.com/a/1190000012729649

Vue2.0父子组件间事件派发机制的更多相关文章

  1. vue2.0 父子组件之间的通信问题

    概要: 父组件向子组件通信:props属性 子组件向父组件通信:$emit()触发事件,$on()监听事件 在 vue 1.0 中可以使用$dispatch 和 $broadcast来实现 向上派发事 ...

  2. Vue2.0父子组件之间的双向数据绑定问题解决方案

    对于vue 1.0项目代码,如果把vue换成vue 2.0,那么之后项目代码就完全奔溃不能运行,vue 2.0在父子组件数据绑定的变化(不再支持双向绑定)颠覆了1.0的约定,很遗憾. 解决方案只有两种 ...

  3. vue2.0 父子组件数据传递prop

    vue的一个核心概念就是组件,而组件实例的作用域是孤立的,所以组件之间是不能直接引用其他组件的数据的.极端点举例来说,就是可以在同一个项目中,每一个组件内都可以定义相同名称的数据. data () { ...

  4. vue2.0父子组件通信的方法

    vue2.0组件通信方法:props传值和emit监听.(.sync方法已经移除.详情请点击)(dispatch-和-broadcast方法也已经废弃) props方法传值:Props 现在只能单项传 ...

  5. vue2.0父子组件以及非父子组件通信传参详解

    1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: <parent> <child :child-msg="msg" ...

  6. vue2.0父子组件以及非父子组件如何通信

    1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: <parent> <child :child-msg="msg" ...

  7. vue2.0父子组件之间通信

    父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...

  8. vue2.0 父子组件通信 兄弟组件通信

    父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...

  9. Vue2.0父子组件之间和兄弟组件之间的数据交互

    熟悉了Vue.js的同级组件之间通信,写此文章,以便记录. Vue是一个轻量级的渐进式框架,对于它的一些特性和优点,请在官网上进行查看,不再赘述. 使用NPM及相关命令行工具初始化的Vue工程,目录结 ...

随机推荐

  1. Vue学习之路第十篇:简单计算器的实现

    前面九篇讲解了vue的一些基础知识,正所谓:学以致用,今天我们将用前九篇的基础知识,来模拟实现计算器的简单功能,项目价值不高,纯粹是为了加深掌握所学知识. 学前准备: 需要掌握JavaScript的e ...

  2. BZOJ 3307 雨天的尾巴 (树上差分+线段树合并)

    题目大意:给你一棵树,树上一共n个节点,共m次操作,每次操作给一条链上的所有节点分配一个权值,求所有节点被分配到所有的权值里,出现次数最多的权值是多少,如果出现次数相同就输出最小的. (我辣鸡bzoj ...

  3. Vue系列(一):简介、起步、常用指令、事件和属性、模板、过滤器

    一. Vue.js简介 1. Vue.js是什么 Vue.js也称为Vue,读音/vju:/,类似view,错误读音v-u-e 是一个轻量级MVVM(Model-View-ViewModel)框架,和 ...

  4. C 语言中函数的跳转

    1.同一个函数内,可以使用goto语句: eg: void  text_1( void ) { char i=0; a : i++; printf ( " text_1 = %d \r\n& ...

  5. HDU 3073 Saving Beans

    Saving Beans Time Limit: 3000ms Memory Limit: 32768KB This problem will be judged on HDU. Original I ...

  6. 2015 Multi-University Training Contest 7 hdu 5379 Mahjong tree

    Mahjong tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  7. LeetCode104_MaximumDepthofBinaryTree Java题解

    题目: Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the ...

  8. POJ 1430

    上面的估计是题解吧....呃,如果真要用到公式的话,确实没听过.... #include <iostream> #include <cstdio> #include <a ...

  9. Android中的单位

    Android中的单位 1.px 像素(pixels) VGA 480*640像素 (Video Graphics Array) QVGA 240*320像素 (Quarter VGA) HVGA 3 ...

  10. leetCode(46):Kth Smallest Element in a BST

    Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...