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 相关文章推荐
面向对象Javascript核心支持代码分享
May 23 Javascript
百度地图自定义控件分享
Mar 04 Javascript
jQuery判断多个input file 都不能为空的例子
Jun 23 Javascript
JavaScript的Vue.js库入门学习教程
May 23 Javascript
JS弹出窗口插件zDialog简单用法示例
Jun 12 Javascript
Bootstrap文件上传组件之bootstrap fileinput
Nov 25 Javascript
微信小程序开发之圆形菜单 仿建行圆形菜单实例
Dec 12 Javascript
ES6中Iterator与for..of..遍历用法分析
Mar 31 Javascript
Bootstrap4如何定制自己的颜色和风格
Feb 26 Javascript
JS实现图片转换成base64的各种应用场景实例分析
Jun 22 Javascript
前端面试知识点目录一览
Apr 15 Javascript
微信小程序之数据绑定原理解析
Aug 14 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学习笔记 PHP面向对象的程序设计
2011/06/13 PHP
表格展示无限级分类(PHP版)
2012/08/21 PHP
php计算十二星座的函数代码
2012/08/21 PHP
jQuery 行级解析读取XML文件(附源码)
2009/10/12 Javascript
使用javascript获取flash加载的百分比的实现代码
2011/05/25 Javascript
JS中的log对象获取以及debug的写法介绍
2014/03/03 Javascript
jQuery学习笔记之 Ajax操作篇(二) - 数据传递
2014/06/23 Javascript
jquery库文件略庞大用纯js替换jquery的方法
2014/08/12 Javascript
JavaScript中的类(Class)详细介绍
2014/12/30 Javascript
js兼容火狐显示上传图片预览效果的方法
2015/05/21 Javascript
angular2使用简单介绍
2016/03/01 Javascript
微信小程序 教程之wxapp 视图容器 view
2016/10/19 Javascript
javascript设置文本框光标的方法实例小结
2016/11/04 Javascript
jQuery插件HighCharts绘制的2D堆柱状图效果示例【附demo源码下载】
2017/03/14 Javascript
ES6 Promise对象概念与用法分析
2017/04/01 Javascript
AngualrJs清除定时器遇到的坑
2017/10/13 Javascript
webpack配置导致字体图标无法显示的解决方法
2018/03/06 Javascript
详解基于Vue,Nginx的前后端不分离部署教程
2018/12/04 Javascript
微信小程序日历效果
2018/12/29 Javascript
JavaScript实现随机点名器实例详解
2019/05/07 Javascript
[04:19]完美世界携手游戏风云打造 卡尔工作室模型介绍篇
2013/04/24 DOTA
Python tkinter模块弹出窗口及传值回到主窗口操作详解
2017/07/28 Python
JSONLINT:python的json数据验证库实例解析
2017/11/28 Python
python使用Turtle库绘制动态钟表
2018/11/19 Python
python 实现一次性在文件中写入多行的方法
2019/01/28 Python
对Python中的条件判断、循环以及循环的终止方法详解
2019/02/08 Python
django2.0扩展用户字段示例
2019/02/13 Python
Spark处理数据排序问题如何避免OOM
2020/05/21 Python
HTML5 video标签(播放器)学习笔记(二):播放控制
2015/04/24 HTML / CSS
英国领先的在线礼品店:Getting Personal
2019/09/24 全球购物
会计学财务管理专业个人的自我评价
2013/10/19 职场文书
syb养殖创业计划书
2014/01/09 职场文书
个人考核材料
2014/05/15 职场文书
教师个人成长总结
2015/02/11 职场文书
实习班主任自我评价
2015/03/11 职场文书
2015年助理工程师工作总结
2015/04/03 职场文书