Vue3组件通信
- 父子组件之间的通信
- 兄弟组件之间的通信
- 祖孙与后代组件之间的通信
- 非关系组件间之间的通信
- 通过 props 传递
- 通过 $emit 触发自定义事件
- 使用 ref
- EventBus
$parent或$root- Provide 与 Inject
- Vuex或pinia
Props
- 父—>子
- 父组件在标签中使用子组件标签字面量进行数据传递
- 子组件通过defineprops([])接受对应标签字面量
father.vue
<Child info="父组件传递的名称" :messageToChildren="message"></Child>
<script setup lang="ts">
//props:可以实现父子组件通信,props数据还是只读的!!!
import Child from "./Child.vue";
import { ref } from "vue";
let message = ref<string>("这是父组件传递给子组件的信息");
</script>
children.vue
<h1>子组件children</h1>
<h1>{{ props.info }}</h1>
<span>{{ props.messageToChildren }}</span>
<script setup lang="ts">
// 接受数据
let props = defineProps(["info", "messageToChildren"]);
</script>
$emit触发自定义事件
- ==子——>父==
- 子组件通过
defineEmits触发自定义事件,$emit第二个参数为传递的数据 - 父组件绑定监听器获取到子组件传递过来的参数
father.vue
<template>
<div>
<h1>这里是父组件</h1>
<Event1 @childrenToFatherMessage="fatherGetChildrenMessage" />
</div>
</template>
<script setup lang="ts">
//引入子组件
import Event1 from "./Event1.vue";
// 绑定事件,调用的事件就是自定义事件
// childrenToFatherMessage:自定义事件
// fatherGetChildrenMessage:触发的回调
// message1,message2对应子组件带来的两个参数
const fatherGetChildrenMessage = (message1: any, message2: any) => {
console.log(message1, message2);
};
</script>
children.vue
<p>我是子组件1</p>
<button @click="changeChildren">点击我执行自定义事件children</button>
<script setup lang="ts">
let $emit = defineEmits(["childrenToFatherMessage"]);
const changeChildren = () => {
// 这里的childrenToFatherMessage是事件类型,后面都为传入的数据
$emit("childrenToFatherMessage", "子组件给父组件传递的数据1", "子组件给父组件传递的数据2");
};
</script>
Event-Bus
- 兄弟间传值
- 创建中央事件总栈
EventBus - 兄弟组件通过
$emit触发自定义事件,$emit第二个参数为传递的数值 - 另一个兄弟组件通过
$on监听自定义事件
插件mitt
-
下载引入mitt:
pnpm i mitt -s -
注册使用
// 引入mitt插件:mitt一个方法,方法执行会返回bus对象 import mitt from 'mitt' const $bus = mitt() export default $bus
children01.vue
<h2>我是子组件01</h2>
<button @click="handler">点击我给02送一台法拉利</button>
<script setup lang="ts">
// 引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
// 传入的数据是一个对象
$bus.emit('car',{car:"法拉利"});
}
</script>
children02.vue
<div class="child1">
<h3>我是子组件02</h3>
<script setup lang="ts">
import $bus from "../../bus";
// 组合式API函数
import { onMounted } from "vue";
// 组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
// 第一个参数:即为事件类型 第二个参数:即为事件回调
$bus.on("car", (car) => {
console.log(car);
});
});
</script>
$parent
$root或ref
- ** 父子传值**
- 通过共同祖辈
$parent或者$root搭建通信桥梁 - $parent:可以在子组件获取父组件的实例,作为传递参数
- ref:在父组件获取子组件的实例
son.vue
<h3>我是子组件:曹植{{money}}</h3>
<script setup lang="ts">
import {ref} from 'vue';
// 儿子钱数
let money = ref(666);
const fly = ()=>{
console.log('我可以飞');
}
// 组件内部数据对外关闭的,别人不能访问
// 如果想让外部访问需要通过defineExpose方法对外暴露
defineExpose({
money,
fly
})
</script>
son02.vue
<h1>我是闺女曹杰{{money}}</h1>
<button @click="handler($parent)">点击我爸爸给我10000元</button>
<script setup lang="ts">
import {ref} from 'vue';
//闺女钱数
let money = ref(999999);
//闺女按钮点击回调
const handler = ($parent)=>{
money.value+=10000;
$parent.money-=10000;
}
</script>
father.vue
<h1>我是父亲曹操:{{money}}</h1>
<button @click="handler">找我的儿子曹植借10元</button>
<Son ref="son"></Son>
<Dau></Dau>
<script setup lang="ts">
// ref:可以获取真实的DOM节点,可以获取到子组件实例VC
// $parent:可以在子组件内部获取到父组件的实例
// 引入子组件
import Son from './Son.vue'
import Dau from './Daughter.vue'
import {ref} from 'vue';
// 父组件钱数
let money = ref(100000000);
// 获取子组件的实例
let son = ref();
// 父组件内部按钮点击回调
const handler = ()=>{
money.value+=10;
// 儿子钱数减去10
son.value.money-=10;
son.value.fly();
}
// 对外暴露
defineExpose({
money
})
</script>
Provide与inject
provide:用于提供后代组件注入的值
inject:用于声明要通过从上层提供方匹配并注入进当前组件的属性。
- 在祖先组件注入祖先组件提供数据,需要的参数就是祖先需要的key
- 如果后代需要使用通过inject进行注入
grandChild.vue
<h1>孙子组件</h1>
<!-- 一开始是获取祖先的car:法拉利 -->
<p>{{car}}</p>
<button @click="updateCar">更新数据</button>
<script setup lang="ts">
import {inject} from 'vue';
// 注入祖先组件提供数据
// 需要参数:即为祖先提供数据的key
let car = inject('TOKEN');
const updateCar = () =>{
car.value = '自行车';
}
</script>
children.vue
<h1>我是子组件1</h1>
<grandChild></grandChild>
<script setup lang="ts">
import grandChild from './GrandChild.vue';
</script>
provide-inject
<h1>Provide与Inject{{car}}</h1>
<Child></Child>
<script setup lang="ts">
import Child from "./Child.vue";
//vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
import { ref, provide } from "vue";
let car = ref("法拉利");
//祖先组件给后代组件提供数据
//两个参数:第一个参数就是提供的数据key
//第二个参数:祖先组件提供数据
provide("TOKEN", car);
</script>
vuex
- 适用场景: 复杂关系的组件数据传递
Vuex作用相当于一个用来存储共享变量的容器state用来存放共享变量的地方getter,可以增加一个getter派生状态,(相当于store中的计算属性),用来获得共享变量的值mutations用来存放修改state的方法。(在pinia中舍弃了mutations,组件变量的变动回直接回影响仓库存储的变量)actions也是用来存放修改state的方法,不过action是在mutations的基础上进行。常用来做一些异步操作
Vuex生命周期:
- 组件dispatch发送请求
- 异步操作后对结果进行提交,有mutations小仓库进行变量的修改
- 修改后最后的值存储在state当中
- 结果最终通过组件呈现
也可以使用pinia,具体实现参照官方文档详细解释
小结
- 父子关系的组件数据传递选择
props与$emit进行传递,也可选择ref - 兄弟关系的组件数据传递可选择
$bus,其次可以选择$parent进行传递 - 祖先与后代组件数据传递可选择
attrs与listeners或者Provide与Inject - 复杂关系的组件数据传递可以通过
vuex存放共享的变量