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 相关文章推荐
flash javascript之间的通讯方法小结
Dec 20 Javascript
JavaScript 组件之旅(二)编码实现和算法
Oct 28 Javascript
jsp+javascript打造级连菜单的实例代码
Jun 14 Javascript
动态加载iframe时get请求传递中文参数乱码解决方法
May 07 Javascript
js监听鼠标点击和键盘点击事件并自动跳转页面
Sep 24 Javascript
使用JS批量选中功能实现更改数据库中的status状态值(批量展示)
Nov 22 Javascript
javascript稀疏数组(sparse array)和密集数组用法分析
Dec 28 Javascript
详解webpack 配合babel 将es6转成es5 超简单实例
May 02 Javascript
微信小程序自定义对话框弹出和隐藏动画
Jul 19 Javascript
[原创]微信小程序获取网络类型的方法示例
Mar 01 Javascript
uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能
Nov 12 Javascript
vue数据响应式原理知识点总结
Feb 16 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通过array_merge()函数合并关联和非关联数组的方法
2015/03/18 PHP
Yii2使用dropdownlist实现地区三级联动功能的方法
2016/07/18 PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
2017/05/20 PHP
记录Yii2框架开发微信公众号遇到的问题及解决方法
2018/07/20 PHP
[原创]用javascript实现检测指定目录是否存在的方法
2008/01/12 Javascript
Jquery 表单取值赋值的一些基本操作
2009/10/11 Javascript
基于jquery的时间段实现代码
2012/08/02 Javascript
JavaScript对数字的判断与处理实例分析
2015/02/02 Javascript
javascript中hasOwnProperty() 方法使用指南
2015/03/09 Javascript
jQuery获得子元素个数的方法
2015/04/14 Javascript
jquery显示loading图片直到网页加载完成的方法
2015/06/25 Javascript
JS正则表达式修饰符global(/g)用法分析
2016/12/27 Javascript
JavaScript实现简易的天数计算器实例【附demo源码下载】
2017/01/18 Javascript
vue-cli开发环境实现跨域请求的方法
2018/04/07 Javascript
js form表单input框限制20个字符,10个汉字代码实例
2019/04/12 Javascript
vue中keep-alive组件的入门使用教程
2019/06/06 Javascript
vuex实现数据状态持久化
2019/11/11 Javascript
[01:05:00]2018国际邀请赛 表演赛 Pain vs OpenAI
2018/08/24 DOTA
Python读取图片EXIF信息类库介绍和使用实例
2014/07/10 Python
在Python中使用dict和set方法的教程
2015/04/27 Python
python寻找list中最大值、最小值并返回其所在位置的方法
2018/06/27 Python
python实现简单日期工具类
2019/04/24 Python
softmax及python实现过程解析
2019/09/30 Python
Python并发请求下限制QPS(每秒查询率)的实现代码
2020/06/05 Python
浅谈Python中的生成器和迭代器
2020/06/19 Python
python 常见的排序算法实现汇总
2020/08/21 Python
css3之UI元素状态伪类选择器实例演示
2017/08/11 HTML / CSS
HTML5 Canvas阴影使用方法实例演示
2013/08/02 HTML / CSS
美国知名的在线旅游服务网站:Priceline
2016/07/23 全球购物
数据库测试通常都包括哪些方面
2015/11/30 面试题
助人为乐表扬信范文
2014/01/14 职场文书
给幼儿园老师的表扬信
2014/01/19 职场文书
药店主任岗位责任制
2014/02/10 职场文书
大学生创业项目方案
2014/03/08 职场文书
老龄工作先进事迹
2014/08/15 职场文书
道歉的话怎么说
2015/05/12 职场文书