Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)


Posted in Javascript onApril 17, 2019

前言

除了使用 Vuex 方法外,vue 提供了各种各样的组件间通信的方案。文章整理一下父子组件、兄弟组件、祖先后代组件间是如何通信的。 ?

? 父子组件通信

props 和 $emit 父子组件通信

子组件有时需要与父组件进行沟通,沟通的方式就是子组件 emit 事件,父组件通过监听这个事件来做进一步动作。而父组件与子组件通信则使用 props

假设这里有一个父组件并引入了一个子组件 my-comp:

<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg"></my-comp>

父组件有一系列 msg 数据需要通过子组件渲染,将 msg 作为 prop 传递给子组件即可:

import MyComp from '@/components/MyComp.vue'

export default {
 name: 'home',
 components: {
 MyComp
 },
 data () {
 return {
 msgs: [{
 id: 1, data: 'hello js'
 }, {
 id: 2, data: 'css world'
 }, {
 id: 3, data: 'animated style'
 }]
 }
 }
}

我们通过点击子组件每一项触发一个事件,父组件监听这个事件去动态改变子组件的 color 样式,这就是父组件监听子组件事件,事件处理函数可以从子组件传递值给父组件:

<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg" :colored="colored" @handle-change-color="handleChangeColor"></my-comp>

首先增加一个事件 handle-change-color 当这个事件被触发时修改名为 color 的 data,然后将 colored 通过 props 传入到子组件:

import MyComp from '@/components/MyComp.vue'

export default {
 name: 'home',
 components: { // 注册组件
 MyComp
 },
 data () {
 return {
 colored: false, // 状态
 msgs: [{
 id: 1, data: 'hello js'
 }, {
 id: 2, data: 'css world'
 }, {
 id: 3, data: 'animated style'
 }]
 }
 },
 methods: {
 handleChangeColor () {
 this.colored = !this.colored // 监听事件动态改变 colored
 }
 // handleChangeColor (param) { // 子组件触发的事件可能包含参数
 }
}

然后编辑子组件:

<div>
 <div @click="handleClick" :style="{color}">
 {{msg.id}} - {{msg.data}} ⭕
 </div>
</div>

首先渲染数据,并监听 click 点击事件,当点击触发事件处理函数 handleClick

export default {
 name: 'MyComp',
 computed: {
 color () { // color 为样式
 return this.colored ? 'red' : 'black' // 根据父组件传入的 props 动态修改样式
 }
 },
 props: ['msg', 'colored'],
 methods: {
 handleClick (e) {
 this.$emit('handle-change-color') // 使用 $emit 方法触发父组件 handle-change-color 事件
 // this.$emit('handler', 'param') // 还可以给事件传递参数
 }
 }
}

子组件接收 colored 父组件传递来的 prop,返回一个计算后的属性 color,根据 colored 返回不同样式。handleClick 处理当子组件元素被点击时 $emit 派发父组件的 handle-change-color 事件

效果如下:

Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)

父组件 $children 操作子组件

使用 $children 操作子组件。如上述例子中,colored 被定义在父组件中,可以将其移动到子组件中,并在父组件通过 $children 访问到子组件:

<template>
 <div @click="handleClick" class="home">
 <my-comp v-for="msg in msgs" :key="msg.id" :msg="msg"></my-comp>
 </div>
</template>

handleClick 事件被放置在 div 中

import MyComp from '@/components/MyComp.vue'

export default {
 // ...
 data () {
 return {
 msgs: [{
  // ...
 }]
 }
 },
 methods: {
 handleClick () {
 this.$children.forEach(child => {
 child.$data.colored = !child.$data.colored // 逐一控制子组件的 $data
 })
 }
 }
}

在子组件中不需要 $emit 事件,只需维护一个 data:

export default {
 name: 'MyComp',
 data () {
 return {
 colored: false // colored 状态
 }
 },
 computed: {
 color () {
 return this.colored ? 'red' : 'black'
 }
 },
 props: ['msg']
}

子组件 $parent 访问父组件

子组件可通过 $parent 来修改父组件的 $data,因此 colored 定义在父组件中。

<template>
 <div class="home">
 <my-comp v-for="msg in msgs" :key="msg.id" :msg="msg" :colored="colored"></my-comp>
 </div>
</template>

通过 prop 传递 colored 参数给子组件

import MyComp from '@/components/MyComp.vue'

export default {
 name: 'home',
 components: {
 MyComp
 },
 data () {
 return {
 colored: false, // 父组件维护一个 colored 状态
 msgs: [{
  // ...
 }]
 }
 }
}

父组件定义 colored 状态

<template>
 <div>
 <div @click="handleClick" :style="{color}">
 {{msg.id}} - {{msg.data}} ⭕
 </div>
 </div>
</template>

子组件渲染 msg 并监听 click 事件

export default {
 // ...
 props: ['msg', 'colored'],
 methods: {
 handleClick (e) {
 this.$parent.$data.colored = !this.$parent.$data.colored
 }
 }
}

通过 $parent 访问父组件,并修改 $data 状态

非父子组件通信

中央事件总线

我们可以使用使用中央事件总线来处理非父子组件间的通信

具体步骤是创建一个 Vue 实例,然后 $on 监听事件,$emit 来派发事件

// src/eventBus.js

import Vue from 'vue'
export default new Vue()

首先创建并导出一个 Vue 实例

import bus from '@/eventbus'

export default {
 // ...
 methods: {
 handleClick (e) {
  bus.$emit('change-color')
 }
 }
}

后代元素 $emit 触发 eventBus 的事件

import bus from '@/eventbus'

export default {
 // ...
 mounted () {
 bus.$on('change-color', () => {
  this.colored = !this.colored
 })
 }
}

祖先元素 $on 方法监听 eventBus 的事件

provide/inject

适用于祖先和后代关系的组件间的通信,祖先元素通过 provide 提供一个值,后代元素则通过 inject 获取到这个值。这个值默认是非响应的,如果是对象那么则是响应式的:

export default {
 name: 'home',
 provide () {
 return {
  colored: this.colored // 依赖于 data
 }
 },
 components: {
 MyComp
 },
 data () {
 return {
  colored: { // 必须为对象
  value: false
  },
  msgs: [{
// ...

首先通过 provide 对外提供一个 colored,这个属性依赖于 data 中的 colored,该变量必须为一个对象,才是响应式的。

⚠️ 必须为一个对象

methods: {
 handleChangeColor () {
  this.colored.value = !this.colored.value
 }
 }

祖先组件监听事件或其他途径去修改 data 改变状态。

export default {
 name: 'MyComp',
 inject: ['colored'], // inject colored
 computed: {
 color () {
  return this.colored.value ? 'red' : 'black' // do more...
 }
 },
// ...

后代组件通过 inject 获取到祖先组件提供的对象,根据对象做进一步动作。

$root 直接访问根组件

根据官方的文档,我们可以通过 $root 来直接访问到 Vue 实例

比方说将数据存储在 Vue 实例中:

// src/main.js

new Vue({
 data () {
 return { // 在这里!!
  colored: false
 }
 },
 router,
 store,
 render: h => h(App)
}).$mount('#app')

然后我们在其他各个组件中都能够使用:

export default {
 name: 'MyComp',
 // ...
 mounted () {
 console.log(this.$root) // 直接访问到根组件
 },
 // ...
}

Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
jQuery 1.2.x 升? 1.3.x 注意事项
May 06 Javascript
jquery判断字符输入个数(数字英文长度记为1,中文记为2,超过长度自动截取)
Oct 15 Javascript
setTimeout和setInterval的区别你真的了解吗?
Mar 31 Javascript
jqGrid日期格式的判断示例代码(开始日期与结束日期)
Nov 08 Javascript
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
Dec 20 Javascript
学习JavaScript设计模式(代理模式)
Dec 03 Javascript
最全面的JS倒计时代码
Sep 17 Javascript
JS获取鼠标坐标并且根据鼠标位置不同弹出不同内容
Jun 12 Javascript
Vue2.0实现调用摄像头进行拍照功能 exif.js实现图片上传功能
Apr 28 Javascript
如何利用node.js开发一个生成逐帧动画的小工具
Dec 01 Javascript
详细介绍解决vue和jsp结合的方法
Feb 06 Javascript
详解nginx配置vue h5 history去除#号
Nov 09 Javascript
详解vue-cli+element-ui树形表格(多级表格折腾小计)
Apr 17 #Javascript
抖音上用记事本编写爱心小程序教程
Apr 17 #Javascript
基于JS实现web端录音与播放功能
Apr 17 #Javascript
vue-cli的build的文件夹下没有dev-server.js文件配置mock数据的方法
Apr 17 #Javascript
vue component 中引入less文件报错 Module build failed
Apr 17 #Javascript
Vue项目路由刷新的实现代码
Apr 17 #Javascript
vue cli 3.x 项目部署到 github pages的方法
Apr 17 #Javascript
You might like
php正则
2006/07/07 PHP
收集的PHP中与数组相关的函数
2007/03/22 PHP
php实现在站点里面添加邮件发送的功能
2020/04/28 PHP
javascript 检测浏览器类型和版本的代码
2009/09/15 Javascript
autoPlay 基于jquery的图片自动播放效果
2011/12/07 Javascript
JavaScript中setInterval的用法总结
2013/11/20 Javascript
javascript白色简洁计算器
2015/05/04 Javascript
Bootstrap作品展示站点实战项目2
2016/10/14 Javascript
Javascript 使用ajax与C#获取文件大小实例详解
2017/01/13 Javascript
jQuery无刷新上传之uploadify简单代码
2017/01/17 Javascript
bootstrap table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)代码分享
2017/01/24 Javascript
微信小程序  TLS 版本必须大于等于1.2问题解决
2017/02/22 Javascript
三步实现ionic3点击退出app程序
2019/09/17 Javascript
构建大型 Vue.js 项目的10条建议(小结)
2019/11/14 Javascript
JS实现进度条动态加载特效
2020/03/25 Javascript
vue中使用echarts的示例
2021/01/03 Vue.js
python自动化测试之连接几组测试包实例
2014/09/28 Python
零基础写python爬虫之HTTP异常处理
2014/11/05 Python
Python控制多进程与多线程并发数总结
2016/10/26 Python
python实现SOM算法
2018/02/23 Python
Python 网络爬虫--关于简单的模拟登录实例讲解
2018/06/01 Python
Python2和Python3之间的str处理方式导致乱码的讲解
2019/01/03 Python
浅谈keras中的batch_dot,dot方法和TensorFlow的matmul
2020/06/18 Python
浅谈HTML5新增及移除的元素
2016/06/27 HTML / CSS
H5 video poster属性设置视频封面的方法
2020/05/25 HTML / CSS
中粮集团旗下食品网上购物网站:我买网
2016/09/22 全球购物
Harrods美国:英国最大的百货公司
2018/11/04 全球购物
财务部岗位职责
2013/11/19 职场文书
素质拓展感言
2014/01/29 职场文书
《鞋匠的儿子》教学反思
2014/03/02 职场文书
群众路线自查报告及整改措施
2014/11/04 职场文书
学校工会工作总结2015
2015/05/19 职场文书
初三化学教学反思
2016/02/22 职场文书
小学生作文之《压岁钱的烦恼》
2019/09/27 职场文书
django 认证类配置实现
2021/11/11 Python
Spring中bean集合注入的方法详解
2022/07/07 Java/Android