前言
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。捞一下【入门级实例讲解上】Vue 2 父子组件通信 - 掘金 (juejin.cn),通过上篇保姆级实例讲解,想必各位有所收获,今天继续整活儿,用超详细的实例演示让你进一步掌握组件间的通信,声明一哈子,这可不仅是父子间传递数据!如果没看到上篇的话,建议看完之后再食用yo~
巩固
-
父向子组件传递数据通过
props,有静态/动态传值之分,区别就是是否通过v-bind绑定。 -
ref是给元素或子组件注册引用信息,通过调用子组件实例中的方法进行数据通信。 -
子向父传递数据通过
$emit事件,子定义事件、传递参数(消息),父通过绑定事件来获取消息。
准备代码
准备三个组件,在父组件中引入两个子组件,并在各自组件之中定义一些后面要用到的数据属性。
Dad.vue父组件
<template>
<div class="dadBox">
<hr>
<p style="color: orangered">消息接收:{{ msg }}</p>
<h2 style="color: brown;">我是父组件</h2>
<broA></broA>
<broB></broB>
</div>
</template>
<script>
import broA from './BroA.vue';
import broB from './BroB.vue';
export default {
name: "Dad",
components: { broA, broB },
data() {
return {
msg: '空'
}
}
}
</script>
BroA.vue子组件A,和组件B互为兄弟组件
<template>
<div class="baBox">
<hr>
<h4 style="color: blue;">我是兄弟组件 A</h4>
<p>props 中的 message:{{ message }}</p>
</div>
</template>
<script>
export default {
name: "BroA",
props: {
message: {
type: String,
default: '默认值'
}
},
data() {
return {
content: '我是来自 BroA 组件的消息!'
}
}
}
</script>
BroB.vue子组件B,和组件A互为兄弟组件
<template>
<div class="bbBox">
<hr>
<h4 style="color: red">我是兄弟组件 B</h4>
<p>消息接收:{{ msg }}</p>
<p>props 中的 message:{{ message }}</p>
</div>
</template>
<script>
export default {
name: "BroB",
props: {
message: {
type: String,
default: '默认值'
}
},
data() {
return {
msg: '空',
content: '我是来自 BroB 组件的消息!'
}
}
}
</script>
父子间通信【补充】
$parent
- 在父组件中定义一个并没有什么卵用的方法,为方便后面演示在子中成功拿到父实例。
// Dad.vue
methods: {
uselessMethod() {
console.log('我是 Dad.vue 组件中一个方法!');
}
}
- 子组件通过
$parent获取父组件实例,并调用其中的方法。
// BroA.vue / BroB.vue
created() {
console.log('父组件实例:', this.$parent);
this.$parent.uselessMethod();
}
- 控制台
这里通过父链
$parent成功在子组件中拿到父组件实例,达到了从父到子的数据通信。
$children
- 在子组件中定义一个并没有什么卵用的方法,为方便后面演示在父中成功拿到子实例数组。
// BroA.vue / BroB.vue
methods: {
uselessMethod() {
console.log('我是 BroA/BroB 子组件中的一个方法!');
}
}
- 父组件通过
$children获得子组件实例数组,并通过迭代调用每个子实例中的方法。
// Dad.vue
created() {
console.log('子组件实例:', this.$children);
this.$nextTick(() => {
this.$children.forEach((child, index) => {
console.log(`第 ${index+1} 个子组件实例:`, child);
child.uselessMethod();
});
});
}
- 控制台
这里通过子链
$children成功在父组件中拿到子组件实例数组,达到了从子到父的数据通信。
以上实例演示了父/子链解决父子组件间的通信问题,它们之间的通信是相互的,并不是单向的。
兄弟组件之间通信
以父组件作为中转实现
- 首先,在兄弟组件 B/A 都行,使用
props自定义属性和绑定触发事件,实现父子之间的相互传值通信。
// BroB.vue
<div class="bbBox">
<button @click="sendMessage">[兄弟组件通信演示]Send message by BroB</button>
</div>
methods: {
sendMessage() {
this.$emit('messageEvent', this.content);
}
}
- 其次,父组件拿到兄弟组件 B/A 传递的消息,作为一个中间人(桥梁)的角色将消息通过兄弟组件使用
props暴露出来属性发送给另一个兄弟组件。
// Dad.vue
<!--将保存起来的消息取出去,父组件向子组件传值通过 props 暴露出来的属性完成-->
<broA :message="msg"></broA>
<broB @messageEvent="getMessage" :message="msg"></broB>
methods: {
// 父组件接收到兄弟组件 B 定义的 messageEvent 事件传递过来的参数(消息)
getMessage(message) {
// 将接收到子组件的消息放到当前实例变量中保存起来
this.msg = message;
}
}
效果演示
暴露 Vue 实例的方式实现
- 编写 JS 文件暴露出 Vue 实例。
import Vue from 'vue'
// 暴露出 Vue 实例
export default new Vue()
- 在互相之间需要通信的组件中引入 JS 文件,引入时是
import xxx from '文件路径'。
/*
☆ import ... from '...' 和 import {...} from '...' 的区别?
注意:
export default ... 的方式,需要通过 import 任意取名 from '文件路径'
错误示范:import {任意取名} from '文件路径'
export const xx = {
...
...
...
}
export function xxx() {
...
...
...
}
...
对于非默认导出,可以导入所需变量、函数...(按需引入)
正确示例:import {xx, xxx, ...} from '文件路径'
错误示例:import { 任意取名(在源文件中并没有定义) } from '源文件路径'
如果需要用到源文件中的所有模块,则通过 import 真.任意取名 from '源文件路径'
错误示例:import {真.任意取名} from '源文件路径'
*/
- 选择一个组件作为消息发送源,使用
xxx.$emit('监听事件名', '发送的消息内容');。
// BroA.vue
<button @click="sendMessage">[bus.js 方式通信演示]Send message by BroA</button>
methods: {
sendMessage() {
// 定义监听事件,传递参数,参数为消息内容,实现发送消息
Bus.$emit('messageEvent', this.content);
}
}
- 组件接收消息,使用
xxx.$on('对应的监听事件名', callback);从回调函数中拿到发送的消息。
mounted() {
// 通过子组件 A 定义的监听事件拿到发送的消息
Bus.$on('messageEvent', (message) => {
// 放到当前实例变量中保存起来
this.msg = message;
});
}
效果演示
跨级通信
要点
- 父组件使用
provide注入数据,注入后可以提供给父组件下的所有子组件。
// Dad.vue
provide() {
return {
providedData: '我是你 Dad (^U^)ノ~YO'
}
}
- 子组件使用
inject取出数据,不过要注意取出的变量名要和注入时的变量名保持一致。
// BroA.vue / BroB.vue
<p>子组件 BroA 接收父组件 provide 的信息:{{ providedData }}</p>
inject: ['providedData']
效果演示
总结
☆ 父子通信
-
父向子组件传递数据通过
props -
子向父传递数据通过
$emit事件 -
父链/子链使用
$parent/$children -
直接访问组件实例用
$refs
☆ 兄弟通信
-
外部
JS文件暴露Vue实例 -
Vuex状态管理
☆ 跨级通信
-
provide/inject父组件只管提供消息,子组件只负责接收 -
外部
JS文件暴露Vue实例 -
Vuex状态管理
结尾
撰文不易,欢迎大家点赞、评论,你的关注、点赞是我坚持的不懈动力,感谢大家能够看到这里!Peace & Love。