面试官:讲一下vue3.0中的组件通信方式

哈喽,大家好,今天这篇文章由我们的金牌导师uncle13提供。

Vue 3.0 中的组件通信方式多样,涵盖了父子组件间、兄弟组件间以及跨组件的通信。下面将详细讲解几种常见的通信方式,并给出简单例子和适用场景。

1. Props(父组件向子组件传递数据)

父组件:

<template>
<div>
<ChildComponent :childData="parentData" />
</div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentData = ref('这是来自父组件的数据');
</script>

子组件(ChildComponent.vue):

<template>
<div>{{ childData }}</div>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
childData: String
});
</script>

适用场景:适用于父组件向子组件传递数据的情况,是Vue中最基本也是最常用的组件通信方式。

2. Custom Events(子组件向父组件传递数据)

子组件:

<template>
<button @click="notifyParent">通知父组件</button>
</template>

<script setup>
import { defineEmits } from 'vue';

const emits = defineEmits(['update:parentData']);

function notifyParent() {
emits('update:parentData', '这是来自子组件的数据');
}
</script>

父组件:

<template>
<div>
<ChildComponent @update:parentData="handleParentDataUpdate" />
<p>父组件接收到的数据:{{ parentReceivedData }}</p>
</div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentReceivedData = ref('');

function handleParentDataUpdate(data) {
parentReceivedData.value = data;
}
</script>

适用场景:适用于子组件需要向父组件发送消息或数据的情况,例如表单提交、按钮点击等事件。

3. Provide / Inject(跨组件传递数据)

祖先组件:

<template>
<div>
<DescendantComponent />
</div>
</template>

<script setup>
import { provide } from 'vue';

provide('ancestorData', '这是来自祖先组件的数据');
</script>

后代组件(DescendantComponent.vue):

<template>
<div>{{ ancestorData }}</div>
</template>

<script setup>
import { inject } from 'vue';

const ancestorData = inject('ancestorData', '默认值');
</script>

适用场景:适用于跨越多层组件的数据传递,特别是在大型应用中,当某些数据需要在多个不直接相关的组件间共享时,provide/inject 提供了非常方便的解决方案。

4. Refs(父组件访问子组件实例)

父组件:

<template>
<div>
<ChildComponent ref="childRef" />
<button @click="accessChildMethod">调用子组件方法</button>
</div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const childRef = ref(null);

function accessChildMethod() {
if (childRef.value) {
childRef.value.childMethod();
}
}
</script>

子组件(ChildComponent.vue):

<script setup>
import { defineExpose } from 'vue';

function childMethod() {
console.log('子组件方法被调用');
}

defineExpose({
childMethod
});
</script>

适用场景:适用于父组件需要直接访问子组件内部数据或方法的情况,但应注意,这种方式会破坏组件的封装性,应谨慎使用。

5. Vuex / Pinia(状态管理)

Vuex 和 Pinia 是 Vue 应用的状态管理模式和库,用于集中管理所有组件的共享状态。它们提供了全局状态存储和跨组件访问状态的能力。

适用场景:适用于大型应用,当多个组件需要共享状态时,使用 Vuex 或 Pinia 可以有效地管理这些状态,并保持应用的可维护性和可扩展性。

6. 使用v-model进行父子组件间的双向数据绑定

父组件:

<template>
<div>
<ChildComponent v-model:childData="parentData" />
<p>父组件的数据:{{ parentData }}</p>
</div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentData = ref('初始数据');
</script>

子组件(ChildComponent.vue):

<template>
<div>
<input v-model="localData" @input="updateValue" />
</div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
modelValue: String
});

const emit = defineEmits(['update:modelValue']);

const localData = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
});

function updateValue(event) {
// 这里通常不需要手动调用,因为v-model已经处理了
// 但如果需要基于输入值做进一步处理后再更新,可以在这里添加逻辑
}
</script>

注意:上面的子组件例子为了简化,没有直接使用v-model:childData的语法,因为Vue 3的v-model在自定义组件上需要显式指定prop和event的名称。在子组件内部,我们使用了computed属性来模拟v-model的行为,但在Vue 3中,你更可能会看到像<ChildComponent v-model:customValue="parentData" />这样的用法,并在子组件内部通过modelValueupdate:modelValue来处理。

适用场景:适用于父子组件间需要双向数据绑定的情况,如表单输入、开关状态等。

7. 使用mittEventBus进行跨组件通信

mitt是一个轻量级的事件发射/订阅库,它可以用作Vue应用中的全局事件总线,实现跨组件通信。虽然Vue 3没有内置EventBus,但你可以通过安装mitt或自己实现一个简单的EventBus来达到相同的效果。

使用mitt的例子:首先,安装mitt

npm install mitt

然后,在项目中创建一个事件总线文件(如eventBus.js):

// eventBus.js
import mitt from 'mitt';
const emitter = mitt();
export default emitter;

在组件中使用:

// 发送事件的组件
<script setup>
import emitter from './eventBus';

function sendMessage() {
emitter.emit('message', 'Hello from anywhere!');
}
</script>

// 监听事件的组件
<script setup>
import { onMounted, onUnmounted } from 'vue';
import emitter from './eventBus';

onMounted(() => {
emitter.on('message', (msg) => {
console.log(msg); // 输出: Hello from anywhere!
});
});

onUnmounted(() => {
emitter.off('message'); // 清理事件监听,避免内存泄漏
});
</script>

适用场景:适用于非父子关系的组件间通信,特别是当这些组件没有直接的父子关系或嵌套关系时。

8. 使用Vue 3的Composition API(如provide/injectref结合)进行复杂通信

虽然provide/inject主要用于跨层级组件的数据传递,但结合ref和Composition API的其他功能(如reactivecomputed等),你可以构建更复杂的通信逻辑。

适用场景:适用于大型应用中,当组件结构复杂且需要跨越多层组件进行数据传递或方法调用时。


最后

还没有使用过我们刷题网站(https://fe.ecool.fun/)或者刷题小程序的同学,如果近期准备或者正在找工作,千万不要错过,题库主打无广告和更新快哦~。

有会员购买、辅导咨询的小伙伴,可以通过下面的二维码,联系我们的小助手。