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 相关文章推荐
js实现权限树的更新权限时的全选全消功能
Feb 17 Javascript
Javascript的常规数组和关联数组对比小结
May 24 Javascript
现如今最流行的JavaScript代码规范
Mar 08 Javascript
jQuery中parents()和parent()的区别分析
Oct 28 Javascript
jQuery焦点控制图层展示延迟隐藏的方法
Mar 09 Javascript
JavaScript常用本地对象小结
Mar 28 Javascript
Jquery树插件zTree实现菜单树
Jan 24 Javascript
Vue.js父与子组件之间传参示例
Feb 28 Javascript
Vue v2.4中新增的$attrs及$listeners属性使用教程
Jan 08 Javascript
vue生命周期与钩子函数简单示例
Mar 13 Javascript
node.js命令行教程图文详解
May 27 Javascript
JavaScript与JQuery框架基础入门教程
Jul 15 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
解析strtr函数的效率问题
2013/06/26 PHP
php使用strtotime和date函数判断日期是否有效代码分享
2013/12/25 PHP
thinkphp中html:list标签传递多个参数实例
2014/10/30 PHP
PHP json_encode() 函数详解及中文乱码问题
2015/11/05 PHP
在页面中js获取光标/鼠标的坐标及光标的像素坐标
2013/11/11 Javascript
用js通过url传参把数据从一个页面传到另一个页面
2014/09/01 Javascript
Node.js中使用mongoskin操作mongoDB实例
2014/09/28 Javascript
什么是 AngularJS?AngularJS简介
2014/12/06 Javascript
js实现登陆遮罩效果的方法
2015/07/28 Javascript
jQuery实现高亮显示网页关键词的方法
2015/08/07 Javascript
基于JS实现EOS隐藏错误提示层代码
2016/04/25 Javascript
jquery插件方式实现table查询功能的简单实例
2016/06/06 Javascript
jquery中用jsonp实现搜索框功能
2016/10/18 Javascript
浅谈js继承的实现及公有、私有、静态方法的书写
2016/10/28 Javascript
jquery实现手机端单店铺购物车结算删除功能
2017/02/22 Javascript
详解vue.js之绑定class和style的示例代码
2017/08/24 Javascript
使用DataTable插件实现异步加载数据
2017/11/19 Javascript
vue左右侧联动滚动的实现代码
2018/06/06 Javascript
JavaScript使用递归和循环实现阶乘的实例代码
2018/08/28 Javascript
vant自定义二级菜单操作
2020/11/02 Javascript
[00:43]DOTA2小紫本全民票选福利PA至宝全方位展示
2014/11/25 DOTA
wxpython中利用线程防止假死的实现方法
2014/08/11 Python
python3实现短网址和数字相互转换的方法
2015/04/28 Python
python下如何查询CS反恐精英的服务器信息
2017/01/17 Python
Python 中urls.py:URL dispatcher(路由配置文件)详解
2017/03/24 Python
Linux RedHat下安装Python2.7开发环境
2017/05/20 Python
PyQt+socket实现远程操作服务器的方法示例
2019/08/22 Python
python Paramiko使用示例
2020/09/21 Python
意大利一家专营包包和配饰的网上商店:Borse Last Minute
2019/08/26 全球购物
说出数据连接池的工作机制是什么?
2013/04/19 面试题
写好自荐信的技巧
2013/11/08 职场文书
自动化专业职业生涯规划书范文
2014/01/16 职场文书
《月亮湾》教学反思
2014/04/14 职场文书
学期评语大全
2014/04/30 职场文书
捐献物资倡议书范文
2014/05/19 职场文书
学雷锋活动简报
2015/07/20 职场文书