这一节我们一起看看 vue 中组件间的数据是如何传递的。

前面,我们已经初步建立了 vue 组件化的思想,知道如何创建组件、引入组件以及如何在组件里的一些功能。接下来,我们来学习怎么建立组件之间的连接,也就是组件的通讯。直白一点说就是:在一个组件中做的操作如何更新到应用程序中的其他组件。

这篇文章会从两个方便介绍 vue 组件间的通讯:

- 父子组件之间的通讯
- 兄弟组件之间的通讯
复制代码

一、父子组件之间的通讯

1、父组件向子组件通讯

vue 中,将数据从父组件传递到子组件,可以用 props 来实现(这一点,在 React 中也是如此)。

props 指的是从外部(父组件)设置的属性。同时,为了告诉 vue 子组件需要从自已的外部(父组件)接收数据,需要在子组件的 vue 对象中设置 props 属性。这个属性是一个 String 数组,每个字符串表示一个可以从父组件接收的属性。

我们需要做两件事情:父组件使用属性绑定、子组件使用 props 对象接收。 看个例子:

  • 父组件使用属性绑定 :
<template><div><ChildCom :list='list' :run='run' :home='this'></ChildCom></div>
</template><script>
import ChildCom from './ChildCom';export default {data() {return {list: ['我是父组件里面的数据', '我来自父组件'],};},components: {ChildCom,},methods: {run() {alert('我是父组件里面的方法'); // eslint-disable-line},},
};
</script>
复制代码

我们在父组件 ParentCom 里面引入了子组件 ChildCom 。为了将数据从父组件传到子组件,我们在子组件 ChildCom 上绑定了几个属性:

<childCom :list='list' :run='run' :home='this'></childCom>
复制代码

绑定属性的时候,属性名前需要加冒号。这里我们绑定了三个属性,父组件的 data 中的 listmethods 中的 run 方法以及指向父组件的 this

  • 子组件使用 props 对象接收 :

接下来,我们创建一个 ChildCom 组件,通过子组件的 props 选项来获得父组件传过来的数据:

<template><div><div class='list'><ul><li v-for='item in list' :key='item'>{{ item }}</li></ul></div><div class='buttons'><button @click='run'>执行父组件的方法</button><button @click='getParent()'>获取父组件的数据和方法</button></div></div>
</template><script>
export default {methods: {getParent() {alert(this.home); // eslint-disable-linealert(this.home.list); // eslint-disable-linealert(this.home.run); // eslint-disable-line},},props: ['list', 'run', 'home'],
};
</script><style lang="postcss" scoped>
.list {margin-bottom: 10px;
}
li {margin: 10px 0;list-style: none;
}
button {padding: 6px;background-color: #35b880;border: none;color: white;font-size: 16px;margin: 5px;
}
</style>
复制代码

子组件的 props 中接收了父组件传递下来的属性。需要注意的是,props 字符串数组中的值(prop)要和在父组件中为子组件绑定属性的属性名保持一致。

这里我们加了一些样式,在 App.vue 中引入父组件 ParentCom ,打开浏览器会看到:

这样,在子组件中就拿到了父组件传递下来的数据和方法以及父组件本身,点击按钮就可以查看到父组件传递给子组件的数据。

2、子组件向父组件通讯

前面我们知道了父组件如何向子组件通讯,那子组件如何向父组件通讯呢?这里介绍两种方式:

  • 子组件触发事件,父组件监听事件并作出数据改变
  • 父组件将变更数据的方法以 props 的形式传给子组件(借鉴 react 的父子通讯方式)
2.1 监听事件

首先在子组件 ChildCom<template> 中添加一个新的标签 button。在这个 button 上添加一个click事件:

<div class='buttons'><!-- add this --><button @click='submit("我是子组件传递给父组件的数据")'>子组件触发更改父组件的数据</button>
</div>
复制代码

当我们点击这个按钮的时候,想要执行 submit 方法,我们在子组件的 <script> 中添加这个方法:

methods: {getParent() {alert(this.home); // eslint-disable-linealert(this.home.list); // eslint-disable-linealert(this.home.run); // eslint-disable-linealert(this.home.appendToList); // eslint-disable-line},// add thissubmit(text) {this.$emit('addItem', text);},
},
复制代码

触发事件时发出($emit)自定义的事件: addItem ,这里我们也给 addItem 事件传递了一个 text 参数。这样就完成了子组件发出自定义事件的过程。

接下来需要在父组件中监听子组件传递的自定义事件 addItem 。怎么做呢?

在父组件中给子组件绑定监听子组件中自定义的事件的方法。这就意味着我们也需要在父组件中定义这个方法。看看代码:

<template><div><ChildCom :list='list' :run='run' :home='this' @addItem='addItem'></ChildCom></div>
</template><script>
import ChildCom from './ChildCom';export default {data() {return {list: ['我是父组件里面的数据', '我来自父组件'],};},components: {ChildCom,},methods: {run() {alert('我是父组件里面的方法'); // eslint-disable-line},addItem(item) {this.list.push(item);},},
};
</script>
复制代码

在子组件上绑定监听子组件中自定义事件的方法需要使用 @ 符号,在 methods 中添加了 addItem 方法。这时候,我们打开浏览器,点击第三个按钮,就会看到子组件向父组件传递的数据了。

2.2 传递 props

传递 props 的意思是说在父组件里面定义改变父组件数据的方法,然后通过 props 传递给子组件,这样子组件就可以触发执行从父组件传递下来的方法,达到更改父组件数据的目的。这种方法借鉴了 React 中组件通讯的方式。看看代码:

我们依旧使用上面的代码,在 ParentCom 组件中将 addItem 方法传递给子组件:

<ChildCom :list='list' :run='run' :home='this' @addItem='addItem' :addItem='addItem'></ChildCom>复制代码

在子组件 ChildCom 中添加一个 button ,在它的点击事件中执行父组件的 addItem 方法,所以,我们也需要在子组件的 props 选项中把 addItem 方法添加进去:

<template><div><div class='list'><ul><li v-for='item in list' :key='item'>{{ item }}</li></ul></div><div class='buttons'><button @click='run'>执行父组件的方法</button><button @click='getParent()'>获取父组件的数据和方法</button><button @click='submit("我是子组件传递给父组件的数据")'>子组件触发更改父组件的数据</button><!-- add this --><button @click='addItem("我是通过子组件props方式传递给父组件的数据")'>子组件触发更改父组件的数据-2</button></div></div>
</template><script>
export default {data() {return {};},methods: {getParent() {alert(this.home); // eslint-disable-linealert(this.home.list); // eslint-disable-linealert(this.home.run); // eslint-disable-linealert(this.home.appendToList); // eslint-disable-line},submit(text) {this.$emit('addItem', text);},},// add thisprops: ['list', 'run', 'home', 'addItem'],
};
</script>
复制代码

打开浏览器,点击 button :

二、兄弟组件之间的通讯

vue 中实现兄弟组件间的通讯主要有两种方法:**通过父组件进行兄弟组件之间通讯、通过 EventHub 进行兄弟组件间通讯。**为了不和上面讲述的父子组件之间通讯的代码混淆,这里我们重新新建组件来演示:

  • 父组件: ParentCard
  • 两个兄弟组件:BrotherCardSisterCard

1、通过父组件进行兄弟组件之间通讯

简单来说,就是让兄弟组件通过一个共同父组件进行通讯。

首先创建父组件 ParentCard

<template><div class='container'><h2>父组件</h2><button @click='stopCommunicate' v-if='showButton'>停止通讯</button><div class='card-body'><brother-card :messageSon='messageson' @brotherSaid='messageDaughter' class='card-brother'></brother-card><sister-card :messageDaughter='messagedaughter' @sisterSaid='messageSon' class='card-sister'></sister-card></div></div>
</template><script>
import BrotherCard from './BrotherCard';
import SisterCard from './SisterCard';export default {name: 'ParentCard',data() {return {messagedaughter: '',messageson: '',};},components: { BrotherCard, SisterCard },methods: {messageDaughter(message) {this.messagedaughter = message;},messageSon(message) {this.messageson = message;},showButton() {return this.messagedaughter && this.messageson;},stopCommunicate() {this.messagedaughter = '';this.messageson = '';},},
};
</script><style scoped>
.container {width: 70%;margin: 10px auto;border-radius: 10px;box-shadow: 1px 1px 1px 1px rgba(50, 50, 93, 0.1),0 5px 15px rgba(0, 0, 0, 0.07) !important;padding: 30px;
}
.card-body {display: flex;justify-content: center;
}
.card-brother,
.card-sister {margin: 0 50px;
}
</style>
复制代码

创建 BrotherCard 组件:

<template><div><div><p>我是子组件:Brother</p><button @click='messageSister'>给妹妹发消息</button><div v-if='messageSon' v-html='messageSon'></div></div></div>
</template><script>
export default {name: 'BrotherCard',props: ['messageSon'],methods: {messageSister() {this.$emit('brotherSaid', 'Hi,妹妹');},},
};
</script>
复制代码

创建 SisterCard 组件:

<template><div><div><p>我是子组件:Sister</p><button @click='messageBrother'>给哥哥发消息</button><div v-if='messageDaughter' v-html='messageDaughter'></div></div></div>
</template><script>
export default {name: 'SisterCard',props: ['messageDaughter'],methods: {messageBrother() {this.$emit('sisterSaid', 'Hi,哥哥');},},
};
</script>
复制代码

结果如下:

在学习完父子组件之间的通讯方法之后,通过父组件进行兄弟组件的通讯就很简单了,其实就是把兄弟之间需要共享的数据提升至他们最近的父组件当中进行管理,将他们的父组件作为中间媒介(在 React 中把这种方式被称为状态提升)。

2、通过EventHub进行兄弟间组件通讯

vue1.0 中,组件之间的通信主要通过 $dispatch 沿着父链向上传播和通过 $broadcast 向下广播来实现。但是在 vue2.0$dispatch$broadcast 已经被弃用。

vue 中也提供了类似 Redux 的组件通信和状态管理方案:vuex。对于中大型的项目来说,使用 vuex 是一个很好的选择。但是对于小型的项目来说,如果一开始就引入了 vuex ,是完全没必要的。

vue 官方文档中也给出了$dispatch$broadcast 最简单的升级方式就是:通过使用事件中心,允许组件自由交流,无论组件处于组件树的哪一层。 vue 文档中把这个事件中心命名为 eventHub,也有很多其他教程中将其命名为 eventBus 。在本教程中,我们统一命名为 eventHub

我们同样基于上面的示例来做修改:ParentCard 组件包含了 SisterCardBrotherCard 两个子组件,而且这两个子组件是兄弟组件。

首先在 main.js 文件中定义一个新的 eventHub 对象(vue 实例 ):

import Vue from 'vue';
import App from './App';
import router from './router';Vue.config.productionTip = false;// add this
export const eventHub = new Vue(); // eslint-disable-line/* eslint-disable no-new */
new Vue({el: '#app',router,components: { App },template: '<App/>',
});
复制代码

接着我们要做的是让 eventHub 实例成为 BrotherCard 组件中发出事件的实例,使用 eventHub.$emit 来替代上例中的 this.$emit(因为 eventHub 是一个 vue 实例,所以它可以使用 $emit 方法)。

<template><div><p>我是Brother组件</p><button @click='messageSister'>给妹妹发消息</button><div v-if='fromSister' v-html='fromSister'></div></div>
</template><script>
import { eventHub } from '../../main';export default {name: 'BrotherCard',data: () => ({fromSister: '',}),methods: {messageSister() {eventHub.$emit('brotherSaid', 'Hi,妹妹');},},/* eslint-disable */created() {eventHub.$on('sisterSaid', message => {this.fromSister = message;});},
};
</script>
复制代码

引入 main.js,并且将 created() 生命周期钩子添加到 BrotherCard 组件中。在 created() 钩子函数中添加 eventHub 启动自定义事件的监听器,监听 sisterSaid 这个动作。

接下来我们改造下 SisterCard 组件,和 BrotherCard 组件的改造是一样的:

<template><div><p>我是Sister组件</p><button @click='messageBrother' class='btn'>给哥哥发消息</button><div v-if='fromBrother' v-html='fromBrother'></div></div>
</template><script>
import { eventHub } from '../../main';export default {name: 'SisterCard',data: () => ({fromBrother: '',}),methods: {messageBrother() {eventHub.$emit('sisterSaid', 'Hi,哥哥');},},/* eslint-disable */created() {eventHub.$on('brotherSaid', message => {this.fromBrother = message;});},
};
</script>
复制代码

这时候,我们就不用在父组件 ParentCard 做任何操作了:

<template><div class='container'><h2>父组件</h2><div class='card-body'><brother-card class='card-brother'></brother-card><sister-card class='card-sister'></sister-card></div></div>
</template><script>
import BrotherCard from './BrotherCard';
import SisterCard from './SisterCard';export default {name: 'ParentCard',components: {'brother-card': BrotherCard,'sister-card': SisterCard,},
};
</script>
复制代码

打开浏览器,可以看到这样也实现了兄弟组件之间的通讯。

三、全局模式

这里的全局模式指的是创建全局变量和全局方法,让其他组件之间共享数据存储的模式。我们看看怎么操作:

先创建一个 store.js ,在这个 JS 文件里创建全局的变量和方法:

const store = {state: { numbers: [1, 2, 3] },addNumber(newNumber) {this.state.numbers.push(newNumber);},
};export default store;
复制代码

storestate 中存放了一个 numbers 数组和一个 addNumber 方法。接下来我们创建两个组件:

  • NumberDisplay 组件:用来显示来自 storenumbers 数组
  • NumberSubmit 组件:允许用户向数据数组中添加一个新的数字

创建 NumberDisplay 组件:

<template><div><h2>{{ storeState.numbers }}</h2></div>
</template><script>
import store from './store';export default {name: 'NumberDisplay',data() {return {storeState: store.state,};},
};
</script>
复制代码

创建 NumberSubmit 组件:

<template><div class='form'><input v-model='numberInput' type='number'><button @click='addNumber(numberInput)'>Add new number</button></div>
</template><script>
import store from './store';export default {name: 'NumberSubmit',data() {return {numberInput: 0,};},methods: {addNumber(numberInput) {store.addNumber(Number(numberInput));},},
};
</script>
复制代码

接着在 GlobalMode.vue 中引用刚才创建的组件:

<template><div><NumberDisplay/><NumberSubmit/></div>
</template><script>
import NumberDisplay from '../components/pass-data-3/NumberDisplay';
import NumberSubmit from '../components/pass-data-3/NumberSubmit';export default {name: 'GlobalMode',components: { NumberDisplay, NumberSubmit },
};
</script>
复制代码

效果如下:

可以看到,我们使用这种方式也可以实现组件间的通讯。

四、总结

最后,我们画个图总结一下 Vue 组件间的通讯:

本节内容代码地址:github.com/IDeepspace/…

欢迎大家关注我的博客:togoblog.cn/

Vue 组件间的通讯相关推荐

  1. 深入解析Vue组件间通信

    React的基本组件元素是一个个组件,组件之间可能存在关联.组合等关系.不同的组件之间,经常会发生数据传递或者交换,我们称之为组件间通信. 根据传递的复杂程度,可以分为三种情况: 父子间通信,兄弟间通 ...

  2. vue组件间通信六种方式

    vue组件间通信六种方式 组件之间的传值通信 组件之间的通讯分为三种:父传子.子传父.兄弟之间的通讯: props/$emit 父传子:主要是通过props来实现的 具体实现:父组件通过import引 ...

  3. vue组件间通信六种方式(完整版)

    前言   组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系:                如上图所示 ...

  4. Vue 组件间通信几种方式(完整版)

    组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系: 如上图所示,A 和 B.B 和 C.B 和 D 都是 ...

  5. Vue 组件间通信方法汇总

    Vue 组件间通信方法汇总 ⭐️ 更多前端技术和知识点,搜索订阅号 JS 菌 订阅 除了使用 Vuex 方法外,vue 提供了各种各样的组件间通信的方案.文章整理一下父子组件.兄弟组件.祖先后代组件间 ...

  6. uniapp 子组件 props拿不到数据_总结下React组件间的通讯

    这是个老话题了. 随着组件化开发成为主流,每个组件都有完善的生命周期,大家可以在生命周期内做一些事情,每个组件有自己的状态管理机制.同时,每个组件都是独立的.这能提高大家的开发效率,规范化开发. 今天 ...

  7. Vue组件间的传值五大场景,你造吗?

    摘要:组件是 vue.js最强大的功能之一,这五个组件间传值场景你了解吗? 本文分享自华为云社区<你了解Vue组件间传值五大场景吗?>,作者:北极光之夜. . 父组件向子组件传值: 比如有 ...

  8. vue组件间通信传递数据的四种方式(路由传参、父子组件传参、兄弟组件传参、深层次传参)

    前言: vue组件间通信对于经常来写vue的伙伴来说应该是很轻松的,对于一些刚入门的伙伴来说可能就有些迷茫,感觉方式有很多种,但是总结起来又不知道应该怎么说,在下面的文章中,我结合自己的开发过程中经常 ...

  9. 面试-vue组件间通信

    说一说vue组件间的通信? 1.props,$emit,sync props父组件绑定传值,子组件声明props接收 props接收值原则上不允许改变,但对于对象属性改变,可能不会被vue检测到 $e ...

最新文章

  1. SimpleHTTPServer中出错信息:SocketServer doesn't handle client disconnects properly
  2. 缓存伪静态html,伪静态缓存(整站静态化)
  3. 带负荷测试要求二次最小电流_检修状态下二次带负荷测试方案的优化研究
  4. 面试问题整理笔记系列 一 Java容器类
  5. php 编译 iconv错误,php编译错误:configure: error: Please reinstall the iconv library.
  6. python动力学仿真_python滑坡动力学
  7. 数据库工作笔记15---Sqlserver2005中的DTS_以及DTS升级成Sqlserver2016的思路
  8. java访问修饰符_Java访问修饰符
  9. 这么好的课程,竟然免费!!!
  10. html按钮的ui,button按钮 - 基础 - H-ui前端框架官方网站
  11. 2021广东工业大学837信号与系统真题自编答案
  12. 变上限积分求导的原理
  13. (45.5)【API接口漏洞】API接口之Web Service测试工具Soap UI PRO、SOAPSonar、Burp Suite、WSSAT、WS-Attacker
  14. 情人节礼物------用她的照片和我们的聊天记录生成词云~
  15. 30个非常流行的提示信息插件(jQuery Tooltip Plugin)
  16. cd28v2虚拟服务器,科技知识:华为荣耀CD28v2路由器初始密码
  17. java好玩的项目github_GitHub 上有些什么好玩的项目?
  18. linux删除历史文件
  19. GEO芯片数据下载和探针ID转换(保姆级教程)
  20. sas连接mysql的server_超简单实现SAS软件 连接 SQL Server

热门文章

  1. 同一局域网内_Pycharm访问服务器
  2. luogu P1064 金明的预算方案
  3. Python--面向对象之组合
  4. jQuery单选按钮监听事件
  5. 浅谈AJAX基本实现流程
  6. 深度学习解决多视图非线性数据特征融合问题
  7. SectionIndexer中的getSectionForPosition()与getPositionForSection()
  8. Android中dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent的理解
  9. ASP.NET DataSet查询结果转换为JSON格式数据
  10. C#中结构数据类型的使用