Vue 组件间的通讯
栏目: JavaScript · 发布时间: 5年前
内容简介:这一节我们一起看看前面,我们已经初步建立了这篇文章会从两个方便介绍
这一节我们一起看看 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
中的 list
、 methods
中的 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-line alert(this.home.list); // eslint-disable-line alert(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
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-line alert(this.home.list); // eslint-disable-line alert(this.home.run); // eslint-disable-line alert(this.home.appendToList); // eslint-disable-line }, // add this submit(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-line alert(this.home.list); // eslint-disable-line alert(this.home.run); // eslint-disable-line alert(this.home.appendToList); // eslint-disable-line }, submit(text) { this.$emit('addItem', text); }, }, // add this props: ['list', 'run', 'home', 'addItem'], }; </script> 复制代码
打开浏览器,点击 button
:
二、兄弟组件之间的通讯
在 vue
中实现兄弟组件间的通讯主要有两种方法:**通过父组件进行兄弟组件之间通讯、通过 EventHub
进行兄弟组件间通讯。**为了不和上面讲述的父子组件之间通讯的代码混淆,这里我们重新新建组件来演示:
- 父组件:
ParentCard
- 两个兄弟组件:
BrotherCard
和SisterCard
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
组件包含了 SisterCard
和 BrotherCard
两个子组件,而且这两个子组件是兄弟组件。
首先在 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> 复制代码
打开浏览器,可以看到这样也实现了兄弟组件之间的通讯。
三、总结
最后,我们画个图总结一下 Vue
组件间的通讯:
本节内容代码地址: github.com/IDeepspace/…
欢迎大家关注我的博客:togoblog.cn/
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Vue组件通讯
- 组件之间的通讯LiveDataBus
- HBase组件内部通讯机制分析
- Vue组件数据通讯新姿势:$attrs 和 $listeners
- 仿iPhone通讯录制作小程序自定义选择组件
- Golang 写的即时通讯服务器 im(服务组件形式)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python学习手册
Mark Lutz / 侯靖 / 机械工业出版社 / 2009-8 / 89.00元
《Python学习手册(第3版)》讲述了:Python可移植、功能强大、易于使用,是编写独立应用程序和脚本应用程序的理想选择。无论你是刚接触编程或者刚接触Python,通过学习《Python学习手册(第3版)》,你可以迅速高效地精通核心Python语言基础。读完《Python学习手册(第3版)》,你会对这门语言有足够的了解,从而可以在你所从事的任何应用领域中使用它。 《Python学习手册(......一起来看看 《Python学习手册》 这本书的介绍吧!