根据任务复杂度不同:

父子组件通信

props传递

  • 父组件:<ChildComponent :prop_name="ref()"></ChildComponent>
  • 子组件:
<script setup>
const props = defineProps({
	prop_name: prop_type, // 如String,Array,Object。
	prop_name: {
		type: String,
		required: true
	},
}); 
// defineProps是setup内置函数
// 如果不需要指定属性,可简写为一行defineProps(['prop_name'])后直接调用
const a = props.prop_name;
</script>

监听事件

例如,要在此处实现无障碍访问的需求,将博客文章的文字能够放大,而页面的其余部分仍使用默认字号。 在父组件中,我们可以添加一个 postFontSize ref 来实现这个效果:

const posts = ref([
  /* ... */
])
 
const postFontSize = ref(1)

在模板中用它来控制所有博客文章的字体大小:

<div :style="{ fontSize: postFontSize + 'em' }">
  <BlogPost
    v-for="post in posts"
    :key="post.id"
    :title="post.title"
   />
</div>

然后,给 <BlogPost> 组件添加一个按钮:

<!-- BlogPost.vue, 省略了 <script> -->
<template>
  <div class="blog-post">
    <h4>{{ title }}</h4>
    <button>Enlarge text</button>
  </div>
</template>

这个按钮目前还没有做任何事情,我们想要点击这个按钮来告诉父组件它应该放大所有博客文章的文字。要解决这个问题,组件实例提供了一个自定义事件系统。父组件可以通过 v-on 或 @ 来选择性地监听子组件上抛的事件,就像监听原生 DOM 事件那样:

<BlogPost
  ...
  @enlarge-text="postFontSize += 0.1"
 />

子组件可以通过调用内置的 $emit 方法,通过传入事件名称来抛出一个事件:

<!-- BlogPost.vue, 省略了 <script> -->
<template>
  <div class="blog-post">
    <h4>{{ title }}</h4>
    <button @click="$emit('enlarge-text')">Enlarge text</button>
  </div>
</template>

因为有了 @enlarge-text="postFontSize += 0.1" 的监听,父组件会接收这一事件,从而更新 postFontSize 的值。

非父子组件通信

要实现在一个组件上hover到文字时,另一个组件中的对应内容改变,你可以使用Vue 3的事件和属性来实现。以下是一个基本的实现方式: 假设你有两个组件:ComponentAComponentB。当在 ComponentA 上的某个文字上hover时,ComponentB 中对应的内容会改变。

<!-- ComponentA.vue -->
<template>
  <div>
	<p @mouseover="handleMouseOver(index)" @mouseleave="handleMouseLeave">Text 1</p>
	<p @mouseover="handleMouseOver(index)" @mouseleave="handleMouseLeave">Text 2</p>
  </div>
</template>
 
<script setup>
import { ref } from 'vue';
 
const hoveredIndex = ref(null);
 
const handleMouseOver = (index) => {
  hoveredIndex.value = index;
};
 
const handleMouseLeave = () => {
  hoveredIndex.value = null;
};
</script>
<!-- ComponentB.vue -->
<template>
  <div>
	<p v-if="hoveredIndex === 0">Content for Text 1</p>
	<p v-else-if="hoveredIndex === 1">Content for Text 2</p>
	<p v-else>No content hovered</p>
  </div>
</template>
 
<script setup>
import { ref } from 'vue';
import ComponentA from './ComponentA.vue';
 
const hoveredIndex = ref(null);
 
// 监听 ComponentA 中 hoveredIndex 的变化
ComponentA.proxy.$watch('hoveredIndex', (value) => {
  hoveredIndex.value = value;
});
</script>

在这个示例中:

  • ComponentA 中的文字被 @mouseover@mouseleave 事件监听,当鼠标移动到文字上时,触发 handleMouseOver 方法,并传递文字的索引,当鼠标离开文字时,触发 handleMouseLeave 方法。这两个方法会设置 hoveredIndex 的值为对应的索引或 null
  • ComponentB 中使用 v-if 指令根据 hoveredIndex 的值来判断显示对应的内容。通过监视 ComponentA 中的 hoveredIndex 的变化,实现了两个组件之间的数据通信 记得将 ComponentAComponentB 都引入到需要的地方,并确保它们在同一个父组件中渲染。

事件总线(Event Bus)

已经淘汰

mitt

在没有复杂到一定情况下时,使用官方推荐的event bus 替代品。

安装

npm install mitt

使用

  1. 创建事件组。建议把一套比较相关的事件放在一起。如emitter.js(同一项目中可以有多个,可以在任何位置,根据你自己的需要进行管理):
import mitt from 'mitt';
const emitter = mitt();
export default emitter;
  1. 发送事件的组件:
<template>
  <button @click="sendMessage">发送消息</button>
</template>
 
<script setup>
import { ref } from 'vue';
import emitter from '../emitter';
 
const sendMessage = () => {
  emitter.emit('message', '你好,我是发送者!');
};
</script>
  1. 接收事件的组件:
<template>
  <div>
    <p>接收到的消息:{{ message }}</p>
  </div>
</template>
 
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import emitter from '../emitter';
 
const message = ref('');
 
onMounted(() => {
  emitter.on('message', (msg) => {
    message.value = msg;
  });
});
 
onUnmounted(() => {
  emitter.off('message');
});
</script>

只要两个组件都引用了同一个事件组的js,就可以通信,无论它们在哪儿

VueX