Vue2.0父子组件间事件派发机制
从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
触发事件类似。不同之处在于,这里可以多级嵌套,不一定是直接的父子组件都可以触发到。
4 .sync 修饰符
在Vue1.x中,利用prop进行"双向绑定",实现父子组件通信,都会用到.sync
修饰符,可以将子组件中对应的prop值变化同步到父组件中。但是,这样就破坏了单向数据流,在2.0版本中被移除了,在2.3.0版本中又以一种语法糖的形式加了进来。
可以看下文档上给出的实例
<comp :foo.sync=“bar”></comp>
被扩展为
<comp :foo="bar" @update:foo= "val =>bar=val"></comp>
其实跟本文中第一种方法基本一致,更加简化了。
同样helloWorld.vue
作为父组件, configBox.vue
作为子组件,
<config-box
:visible.sync="dialogConfigVisible"
> </config-box>
然后在子组件中,显式的触发更新事件:
methods:{
dialogClose() {
this.show = false;
this.$emit("update:visible", false)
}
}
这样visible 的变化就能同步到父组件中了。
原文地址:https://segmentfault.com/a/1190000012729649
Vue2.0父子组件间事件派发机制的更多相关文章
- vue2.0 父子组件之间的通信问题
概要: 父组件向子组件通信:props属性 子组件向父组件通信:$emit()触发事件,$on()监听事件 在 vue 1.0 中可以使用$dispatch 和 $broadcast来实现 向上派发事 ...
- Vue2.0父子组件之间的双向数据绑定问题解决方案
对于vue 1.0项目代码,如果把vue换成vue 2.0,那么之后项目代码就完全奔溃不能运行,vue 2.0在父子组件数据绑定的变化(不再支持双向绑定)颠覆了1.0的约定,很遗憾. 解决方案只有两种 ...
- vue2.0 父子组件数据传递prop
vue的一个核心概念就是组件,而组件实例的作用域是孤立的,所以组件之间是不能直接引用其他组件的数据的.极端点举例来说,就是可以在同一个项目中,每一个组件内都可以定义相同名称的数据. data () { ...
- vue2.0父子组件通信的方法
vue2.0组件通信方法:props传值和emit监听.(.sync方法已经移除.详情请点击)(dispatch-和-broadcast方法也已经废弃) props方法传值:Props 现在只能单项传 ...
- vue2.0父子组件以及非父子组件通信传参详解
1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: <parent> <child :child-msg="msg" ...
- vue2.0父子组件以及非父子组件如何通信
1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: <parent> <child :child-msg="msg" ...
- vue2.0父子组件之间通信
父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...
- vue2.0 父子组件通信 兄弟组件通信
父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...
- Vue2.0父子组件之间和兄弟组件之间的数据交互
熟悉了Vue.js的同级组件之间通信,写此文章,以便记录. Vue是一个轻量级的渐进式框架,对于它的一些特性和优点,请在官网上进行查看,不再赘述. 使用NPM及相关命令行工具初始化的Vue工程,目录结 ...
随机推荐
- Eclipse中使用GIT提交文件至本地
GIT提交文件至本地: 1. 右击项目——Team——Commit…: 2.在弹出的Commit Changes框中——选择要提交的文件——填写提交说明——点击Commit,即可提交至本地.
- Codeforces Round #493 (Div. 2) A. Balloons 贪心水题
由于是输出任意一组解,可以将价值从小到大进行排序,第一个人只选第一个,第二个人选其余的.再比较一下第一个人选的元素和第二个人所选元素和是否相等即可.由于已将所有元素价值从小到大排过序,这样可以保证在有 ...
- 如何使用图形界面Webmin管理linux服务器
出处:http://linux.cn/thread/11992/1/1/ 如何使用图形界面Webmin管理linux服务器 一台典型的linux服务器运行命令行环境中,并已经包括了一些用于安装和配置各 ...
- vue 过滤器使用的传参说明
在table中,需要对obj的数据类型进行文字转换,例如后台接口返回的姓别值:1,2.其中需要页面根据字典需要把1=>男,2=>女进行转换. 以前的习惯是每一个过滤方法都写一个方法进行转换 ...
- python--(常用模块-1)
python--(常用模块-1) 一.模块的简单认识: 什么是模块,模块就是我们把装有特有功能的代码进行归类的结果,从代码编写的单位来看我们的程序,从小到大的顺序:一条代码<语句块<代码块 ...
- centos7下部署Redis
1.1. Redis的安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: 第一步:redis的源码包上 ...
- Spring IOC过程
https://www.processon.com/diagraming/5c96171fe4b0f88919b98497 1. AbstractApplicationContext:执行refres ...
- 2015 Multi-University Training Contest 7 hdu 5372 Segment Game
Segment Game Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tota ...
- Opencv 使用Rect选取与设置窗口ROI
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50593825 首先看一下Rect对象的 ...
- Jquery-ajax错误分析
当我把cshtml中的js代码移出到js文件中,将js代码作为文件引入cshtml时,出现了下面的这样的错误 网上的不少人说是通过在\(.ajax参数中加上async:true解决的,但\).ajax ...