这种方式是父子组件通信最常用的方式。子组件通过 props 属性来接受父组件的数据,父组件在子组件上注册监听事件,子组件通过 emit 触发自定义事件来向父组件发送数据。
// Parent.vue
<template>
<child :msg="msg">child>
template>
// Child.vue
export default {
//props:['msg'],// 写法一
props:{// 写法二
msg:{
type:String,
default:'这是默认数据'
}
}
}
// Parent.vue
<template>
<child @sendMsg="getChildMsg"></child>
</template>
export default {
methods:{
getChildMsg(msg){
console.log(msg) //身体健康
}
}
}
// Child.vue
export default {
data(){
return { msg: "身体健康" }
},
methods: {
handleClick(){
this.$emit("sendMsg",this.msg)//emit触发自定义事件
}
},
}
vue3中子组件通过defineProps获取父组件传递的数据,并且不需要引入,可以直接使用
//Parent.vue
<template>
<Child info="身体健康" :money="money"></Child>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(10000);
</script>
//Child.vue
<template>
<p>{{ info }}</p>
<p>{{ money }}</p>
</template>
<script setup lang="ts">
//使用defineProps方法接受父组件传递过来的数据
const props = defineProps(["info", "money"]); //数组写法
// const props = defineProps({ //对象写法
// info: String,
// money: Number,
// });
</script>
利用defineEmits方法返回函数来触发自定义事件,同样不需要引入,可以直接使用
<template>
<Child @xxx="handler"></Child>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
const handler = (param1: any, param2: any) => {
console.log(param1, param2); //好好学习,天天向上
};
</script>
<template>
<button @click="handler">子传父</button>
</template>
<script setup lang="ts">
//利用defineEmits方法返回函数触发自定义事件
let emit = defineEmits(["xxx"]);
const handler = () => {
emit("xxx", "好好学习", "天天向上");
};
</script>
通过 ref 和 $parent ,也可以实现父子组件通信。
子传父:通过ref属性
//Parent.vue
<template>
<child ref="child"></child>
</template>
<script>
import child from './child.vue'
export default {
components: { child },
mounted () {
console.log(this.$refs.child.name); // 小心
this.$refs.child.sayHello(); // hello
}
}
</script>
// Child.vue
export default {
data () {
return {
name: '小心'
}
},
methods: {
sayHello () {
console.log('hello')
}
}
}
父传子:使用$parent
// Child.vue
export default{
mounted(){
this.$parent.sayHello() // 调用父组件的方法
this.$parent.name // 获取父组件中的属性
}
}
注意点:vue3中使用 script setup 的组件是默认关闭的,外部不能访问,如果想获取要获取某个组件的数据和方法,需要在该组件中通过defineExpose来指定需要对外暴露的属性或方法。
子传父:通过ref父组件获取子组件的属性或者调用子组件方法
// Parent.vue
<template>
<child ref="son"></child>
<button @click="handlerClick">按钮</button>
</template>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const son = ref(null)
const handlerClick = () => {
console.log(son.value.childName) // 1000000000000
}
</script>
// Child.vue
<script setup>
// defineExpose指定需要对外暴露的属性或方法,不需要引入
defineExpose({
money: ”1000000000000“
})
</script>
父传子:通过$parent在子组件中获取父组件的数据和方法
// Parent.vue
<template>
<Child></Child>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(1000000000000);
// defineExpose指定需要对外暴露的属性或方法,不需要引入
defineExpose({
money
});
</script>
// Child.vue
<template>
<div class="dau">
<button @click="handler($parent)">点击获取父组件实例</button>
</div>
</template>
<script setup lang="ts">
const handler = ($parent) => {
console.log($parent.money); //1000000000000
};
</script>
provide / inject 为依赖注入,该方法用于父子组件、隔代组件之间的通信,即在层数很深的情况下,可以使用这种方法来进行传值。就不用一层一层的传递了。
provide / inject是Vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。
// 父组件
export default{
provide(){
return {
msg: this.msg
}
}
}
// 后代组件
export default{
inject:["msg"]
}
要注意的是 provide 和 inject 传递的数据不是响应式的,也就是说用 inject 接收来数据后,provide 里的数据改变了,后代组件中的数据不会改变。
// Parent.vue
<script setup>
import { provide } from "vue"
provide("name", "小心")
</script>
// Child.vue
<script setup>
import { inject } from "vue"
const name = inject("name")
console.log(name) //小心
</script>
eventBus事件总线,本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通过$on
监听事件,通过$emit
触发事件,适用于父子、隔代、兄弟组件通信。
1.创建事件中心管理组件之间的通信
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
2.通过emit触发自定义事件
//兄弟组件A 发送数据
<template>
<button @click="handlerClick">按钮</button>
</template>
export default{
methods:{
handlerClick(){
// 自定义事件名 sendMsg
this.$bus.$emit("sendMsg", "这是要向外部发送的数据")
}
}
}
3.通过on监听事件
//兄弟组件B 接受数据
export default{
mounted(){
// 监听事件的触发
this.$bus.$on("sendMsg", data => {
console.log("这是接收到的数据:", data)
})
},
beforeDestroy(){
// 取消监听
this.$bus.$off("sendMsg")
}
}
Vue3中移除了eventBus,但可以借助mitt插件来实现代替,原理还是 EventBus。
1.首先需要安装插件
npm install --save mitt
2.创建总线对象
//mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt
3.通过emit方法触发自定义事件,on方法监听事件
// 组件 A
<script setup>
import mitt from './mitt'
const handleClick = () => {
mitt.emit('handleChange')
}
</script>
// 组件 B
<script setup>
import mitt from './mitt'
import { onUnmounted } from 'vue'
const someMethed = () => { ... }
mitt.on('handleChange',someMethed)
onUnmounted(()=>{
mitt.off('handleChange',someMethed)
})
使用Vuex或Pinia状态管理器,集中式存储管理所有组件的状态,实现任意组件间的通信。
用法可以参考:Pinia官网,Vuex官网。这里就不再具体展开。
本文结合vue2和vue3写法对比,总结了vue中组件通信常用的几种方式。
写作不易,你的一赞一评,就是我前行的最大动力。如有问题,欢迎指出!