vue3使用vue.js组件间通信

220 阅读2分钟

vue3使用vue.js组件间通信

在 Vue 3 中,组件间通信是开发复杂应用的关键。Vue 3 提供了多种方式来实现组件间的数据传递和通信,以下是常见的组件间通信方式及其使用方法。

  1. Props 和 Events

这是 Vue 中最基础的组件通信方式,适用于父子组件之间的通信。

(1) Props

父组件通过 props 向子组件传递数据。

父组件传递数据

<!-- ParentComponent.vue -->
<template>
  <ChildComponent :message="message" />
</template>

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

const message = ref('Hello from Parent!');
</script>

子组件接收数据

<!-- ChildComponent.vue -->
<template>
  <div>{{ message }}</div>
</template>

<script setup>
defineProps({
  message: String,
});
</script>

(2) Events

子组件通过 $emit 向父组件发送事件。

子组件发送事件

<!-- ChildComponent.vue -->
<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script setup>
const emit = defineEmits(['message']);

const sendMessage = () => {
  emit('message', 'Hello from Child!');
};
</script>

父组件监听事件

<!-- ParentComponent.vue -->
<template>
  <ChildComponent @message="handleMessage" />
</template>

<script setup>
const handleMessage = (message) => {
  console.log(message); // 输出: Hello from Child!
};
</script>
  1. v-model 双向绑定

v-modelpropsevents 的语法糖,用于实现父子组件的双向绑定。

<!-- ParentComponent.vue -->
<template>
  <ChildComponent v-model="message" />
</template>

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

const message = ref('Hello from Parent!');
</script>
<!-- ChildComponent.vue -->
<template>
  <input :value="modelValue" @input="updateValue" />
</template>

<script setup>
defineProps({
  modelValue: String,
});

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

const updateValue = (event) => {
  emit('update:modelValue', event.target.value);
};
</script>
  1. Provide 和 Inject

provideinject 用于跨层级组件通信,父组件通过 provide 提供数据,子孙组件通过 inject 注入数据。

<!-- ParentComponent.vue -->
<template>
  <ChildComponent />
</template>

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

provide('message', 'Hello from Parent!');
</script>
<!-- ChildComponent.vue -->
<template>
  <div>{{ message }}</div>
</template>

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

const message = inject('message');
</script>
  1. Event Bus(事件总线)

通过一个全局的事件总线实现任意组件间的通信。

使用 mitt 实现事件总线

// src/utils/eventBus.js
import mitt from 'mitt';

export const emitter = mitt();
<!-- ComponentA.vue -->
<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script setup>
import { emitter } from '@/utils/eventBus';

const sendMessage = () => {
  emitter.emit('message', 'Hello from Component A!');
};
</script>
<!-- ComponentB.vue -->
<template>
  <div>{{ message }}</div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { emitter } from '@/utils/eventBus';

const message = ref('');

const handleMessage = (data) => {
  message.value = data;
};

onMounted(() => {
  emitter.on('message', handleMessage);
});

onUnmounted(() => {
  emitter.off('message', handleMessage);
});
</script>
  1. Vuex/Pinia(状态管理)

对于复杂的应用,可以使用 Vuex 或 Pinia 进行全局状态管理。

// src/stores/messageStore.js
import { defineStore } from 'pinia';

export const useMessageStore = defineStore('message', {
  state: () => ({
    message: 'Hello from Store!',
  }),
  actions: {
    updateMessage(newMessage) {
      this.message = newMessage;
    },
  },
});
<!-- ComponentA.vue -->
<template>
  <button @click="updateMessage">Update Message</button>
</template>

<script setup>
import { useMessageStore } from '@/stores/messageStore';

const messageStore = useMessageStore();

const updateMessage = () => {
  messageStore.updateMessage('New Message from Component A!');
};
</script>
<!-- ComponentB.vue -->
<template>
  <div>{{ messageStore.message }}</div>
</template>

<script setup>
import { useMessageStore } from '@/stores/messageStore';

const messageStore = useMessageStore();
</script>
  1. refexpose

父组件通过 ref 获取子组件实例,并调用子组件的方法或访问其属性。

<!-- ParentComponent.vue -->
<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildMethod">Call Child Method</button>
</template>

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

const childRef = ref(null);

const callChildMethod = () => {
  childRef.value.childMethod();
};
</script>
<!-- ChildComponent.vue -->
<template>
  <div>Child Component</div>
</template>

<script setup>
const childMethod = () => {
  console.log('Child method called!');
};

defineExpose({
  childMethod,
});
</script>

总结

Vue 3 提供了多种组件间通信的方式,适用于不同的场景:

  • 父子组件通信propseventsv-model

  • 跨层级通信provideinject

  • 任意组件通信:事件总线(如 mitt)。

  • 全局状态管理:Vuex 或 Pinia。

  • 访问子组件实例refexpose

根据具体需求选择合适的通信方式,可以提升代码的可维护性和开发效率。

更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github