一句话总结:Vue3组件通信主要通过Props、Emits、v-model、Provide & Inject、全局状态管理(如Pinia或Vuex)、$refs以及组合式API等方式实现。
props
父组件给子组件传递数据
父组件
<template>
<div>
<h2>父组件</h2>
<Child :car="car" />
</div>
</template>
<script setup lang="ts">
import Child from './Child.vue'
import {ref} from 'vue'
let car = ref('雅迪')
</script>
子组件
<template>
<div>
<h2>子组件</h2>
<div>父组件传递的数据: {{ car }}</div>
</div>
</template>
<script setup lang="ts">
defineProps(["car"]);
</script>
子组件给父组件传递数据
父组件传递一个函数
<template>
<div>
<h2>父组件</h2>
<Child :sendToy="getToy" />
</div>
</template>
<script setup lang="ts">
import Child from './Child.vue'
import {ref} from 'vue'
function getToy(value:string) {
console.log(value);
}
</script>
子组件调用函数并传递数据
<template>
<div>
<h2>子组件</h2>
<button @click="sendToy(toy)">给父组件传递数据</button>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
defineProps(["sendToy"]);
let toy = ref("阿童木");
</script>
父组件给孙组件传递数据
父组件传递数据
<template>
<div>
<h2>父组件</h2>
<Child :car="car" />
</div>
</template>
<script setup lang="ts">
import Child from './Child.vue'
import {ref} from 'vue'
let car = ref("雅迪")
</script>
子组件不接收,就会到$attrs里面,然后传递给孙组件
<template>
<div>
<h2>子组件</h2>
<Grandson :car="$attrs" />
</div>
</template>
<script setup lang="ts">
import Grandson from './Grandson.vue';
</script>
孙组件接收
<template>
<div>
<h2>孙组件</h2>
<div>父传递的数据:{{ car }}</div>
</div>
</template>
<script setup lang="ts">
defineProps(['car'])
</script>
自定义事件
给子组件绑定事件
<template>
<div>
<h2>父组件</h2>
<Child @get-toy="getToy" />
</div>
</template>
<script setup lang="ts">
import Child from './Child.vue'
import {ref} from 'vue'
let car = ref("雅迪")
function getToy(value) {
console.log(value);
}
</script>
子组件声明并调用事件
<template>
<div>
<h2>子组件</h2>
<button @click="setToy">给父组件传递数据</button>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
let toy = ref("阿童木")
const emit = defineEmits(["get-toy"])
function setToy() {
emit("get-toy", toy)
}
</script>
mitt
安装mitt:npm i mitt
utils/emitter.ts
// 引入mitt
import mitt from 'mitt'
// 暴露mitt
export default mitt()
父组件
<template>
<div>
<h2>父组件</h2>
<button @click="sendData">给子组件发送数据</button>
<Child />
</div>
</template>
<script setup lang="ts">
import Child from './Child.vue';
import {ref} from 'vue'
import emitter from '@/utils/emitter';
let car = ref("雅迪")
function sendData() {
// 发送事件
emitter.emit('send-data', car)
}
</script>
子组件
<template>
<div>
<h2>子组件</h2>
<div>父组件给的数据: {{ car }}</div>
</div>
</template>
<script setup lang="ts">
import {ref, onUnmounted} from 'vue'
import emitter from '@/utils/emitter';
let car = ref('')
// 触发事件
emitter.on("send-data", (value:any)=>{
car.value = value
})
// 解绑事件
onUnmounted(()=>{
emitter.off("send-data")
})
</script>
v-model
在组件上面使用v-model,ui组件常用
<template>
<div>
<FatherInput v-model="car" />
</div>
</template>
<script setup lang="ts">
import FatherInput from './FatherInput.vue';
import {ref} from 'vue'
let car = ref("雅迪")
</script>
本质写法
// 父组件
<template>
<div>
<!-- <FatherInput v-model="car" /> -->
<FatherInput :modelValue="car" @updata:modelValue="car = $event" />
</div>
</template>
<script setup lang="ts">
import FatherInput from './FatherInput.vue';
import {ref} from 'vue'
let car = ref("雅迪")
</script>
// 子组件
<template>
<input
type="text"
:value="modelValue"
@input="emit('updata:modelValue',(<HTMLInputElement>$event.target).value)"
/>
</template>
<script lang="ts" setup>
defineProps(["modelValue"]);
const emit = defineEmits(["updata:modelValue"]);
</script>
provide-inject
祖孙传参
// 父组件
<template>
<div>
<h2>父组件</h2>
<Child />
</div>
</template>
<script setup lang="ts">
import Child from './Child.vue';
import {ref, provide} from 'vue'
let car = ref("雅迪")
// 向后代提供数据
provide("car", car)
</script>
// 孙组件
<template>
<div>
<h4>孙组件</h4>
{{ car }}
</div>
</template>
<script setup lang="ts">
import {inject} from 'vue'
// 注入数据
let car = inject('car', "默认值")
</script>