概述
Vue 组件通信是面试和实际开发中的核心知识点,组件通信包括父组件与子组件甚至孙组件的通信,子组件与子组件之间的通信。组件通信详细掌握以下9中方法:
- props
- 自定义事件
- mitt
- v-model
- $attrs
- refs、refs、refs、parent
- provide、inject
- pinia
- slot
props
概述
props是组件通信中最常用的一种方式,常用于父与子之间数据传递
- 父传子,通过数据传递
- 子传父,通过函数传递数据
事例
-
创建父组件App,数据为name、price
-
创建子组件Fish,数据为num
-
父传子数据name、price,父传子函数,子调用函数传数量num
-
子接收数据、函数
<template>
App组件代码</template> <script setup lang="ts"> import { ref } from 'vue'; import Fish from './view/Fish.vue'; let name = ref('鲫鱼'); let price = ref(100); let num = ref(0); function getNum(n: number) { num.value= n; }父组件接收到鱼的数量:{{ num }}
<Fish :fishname="name" :price="price" :getNum="getNum"/>
Fish组件代码
<template>
<div>
<h2>鱼类:{{ fishname }}</h2>
<h2>价格:{{ price }}</h2>
<button @click="getNum(num++)">修改鱼的数据</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
let num = ref(999);
defineProps(['fishname','price','getNum'])
</script>
运行效果

自定义事件
父组件给子组件绑定自定义事件,子组件触发事件,回调父组件函数,传递数据,类似@click。自定义事件只能由子组件传递给父组件
-
父组件传递自定义函数
-
子组件触发自定义函数,传递参数
<template>
App组件代码</template> <script setup lang="ts"> import { ref } from 'vue'; import Fish from './view/Fish.vue'; let name = ref(''); let price = ref(0); function getFish(s:string,p:number) { name.value = s; price.value = p; } </script>父组件接收到鱼:{{ name }}
父组件接收到鱼的价格:{{ price }}
<Fish @get-fish="getFish"/>
Fish组件代码
<template>
<div>
<h2>鱼类:{{ name }}</h2>
<h2>价格:{{ price }}</h2>
<button @click="emit('get-fish',name,price)">修改鱼的数据</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
let name = ref('鲫鱼');
let price = ref(999);
const emit = defineEmits(['get-fish']);
</script>
运行效果:

mitt
概述
mitt是一个第三方库,它可以实现任意组件通信。组件通过订阅接收消息,通过发布传递数据。
- emitter.on(event, handler) 监听事件
- emitter.emit(event, data) 触发事件并传递数据
- emitter.off(event, handler) 移除事件监听
- emitter.all.clear() 清空所有事件
事例
以子组件传递数据,父组件接收数据为例。同理若父组件给数据,子组件接收数据是一样的。
- 安装mitt,npm install mitt
- 创建utils目录,创建emitter.ts
- main.ts引入emitter.ts
- 创建App接收Fish传递数据,
- 创建Fish,发送数据
emitter.ts代码
import mitt from 'mitt'
const emitter = mitt();
export default emitter;
main.ts代码
import { createApp } from 'vue'
import App from './App.vue'
import emitter from './utils/emitter'
console.log(emitter)
const app = createApp(App)
app.mount('#app')
App组件代码
<template>
<div class="app">
<h2>父组件接收到鱼:{{ name }}</h2>
<h2>父组件接收到鱼的价格:{{ price }}</h2>
<Fish/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Fish from './view/Fish.vue';
import emitter from '@/utils/emitter'
let name = ref('');
let price = ref(0);
emitter.on('get-fish', (value:any) => {
console.log(value)
name.value = value.name;
price.value=value.price
})
</script>
Fish组件代码
<template>
<div>
<h2>鱼类:{{ fish.name }}</h2>
<h2>价格:{{ fish.price }}</h2>
<button @click="emitter.emit('get-fish',fish)">修改鱼的数据</button>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import emitter from '@/utils/emitter'
emitter.emit('test',121)
let fish = reactive({
name: '鲫鱼',
price:99
});
</script>
v-model
概述
v-model是双向数据绑定,它的底层是通过props参数modelValue与自定义函数update:modelValue实现的。在子组件接收props参数与自定义函数,就可以实现双向数据绑定。
事例
App代码
<template>
<div class="app">
<h2>父组件接收到鱼:{{ name }}</h2>
<Fish v-model="name"/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Fish from './view/Fish.vue';
let name = ref('鲫鱼');
</script>
Fish代码
<template>
<div>
<h2>鱼类:{{ modelValue }}</h2>
<button @click="changefish">修改鱼的数据</button>
</div>
</template>
<script setup lang="ts">
let props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
function changefish() {
emit('update:modelValue','草鱼')
}
</script>
运行查看结果

注意代码,v-model默认传递props参数是modelValue、自定义函数式update:modelValue,注意有冒号也是个函数。以下修改v-model props名称、自定义函数名称。
事例2修改v-model props名称与自定义函数名称
App源码
<template>
<div class="app">
<h2>父组件接收到鱼:{{ name }}</h2>
<h2>父组件接收到鱼:{{ price }}</h2>
<Fish v-model="name" v-model:price="price"/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Fish from './view/Fish.vue';
let name = ref('鲫鱼');
let price = ref(666);
</script>
Fish源码
<template>
<div>
<h2>鱼类:{{ modelValue }}</h2>
<h2>鱼类:{{ price }}</h2>
<button @click="changefish">修改鱼的数据</button>
</div>
</template>
<script setup lang="ts">
let props = defineProps(['modelValue','price']);
const emit = defineEmits(['update:modelValue','update:price']);
function changefish() {
emit('update:modelValue','草鱼')
emit('update:price','999')
}
</script>
运行效果如下:
