这是最常见的父组件向子组件传递数据的方式。父组件在使用子组件时,通过在子组件标签上绑定属性来传递数据,子组件通过 props
选项接收这些数据。
<!-- 父组件 -->
<template>
<div>
<ChildComponent :parentMsg="message" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const message = ref('来自父组件的消息');
</script>
<!-- 子组件 ChildComponent.vue -->
<template>
<div>
<p>{{ parentMsg }}</p>
</div>
</template>
<script setup>
const props = defineProps({
parentMsg: {
type: String,
required: true
}
});
</script>
子组件可以通过 $emit
触发自定义事件,并将数据作为参数传递给父组件,父组件监听这些自定义事件来接收数据。
<!-- 子组件 ChildComponent.vue -->
<template>
<div>
<button @click="sendDataToParent">发送数据给父组件</button>
</div>
</template>
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['childEvent']);
const sendDataToParent = () => {
const data = '来自子组件的数据';
emit('childEvent', data);
};
</script>
<!-- 父组件 -->
<template>
<div>
<ChildComponent @childEvent="handleChildEvent" />
<p>{{ receivedData }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const receivedData = ref('');
const handleChildEvent = (data) => {
receivedData.value = data;
};
</script>
v-model
是一种语法糖,结合了 props
和 $emit
,可以实现父组件和子组件之间的双向数据绑定。
<!-- 子组件 ChildComponent.vue -->
<template>
<div>
<input v-model="modelValue" @input="updateValue">
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
modelValue: String
});
const emit = defineEmits(['update:modelValue']);
const updateValue = (event) => {
emit('update:modelValue', event.target.value);
};
</script>
<!-- 父组件 -->
<template>
<div>
<ChildComponent v-model="parentValue" />
<p>{{ parentValue }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentValue = ref('初始值');
</script>
事件总线是一个全局的事件发射器,兄弟组件可以通过它来发布和订阅事件,从而实现数据传递。在 Vue 3 中,可使用 mitt
库来实现事件总线。
// eventBus.js
import mitt from 'mitt';
const eventBus = mitt();
export default eventBus;
<!-- 发送数据的兄弟组件 -->
<template>
<div>
<button @click="sendData">发送数据</button>
</div>
</template>
<script setup>
import eventBus from './eventBus.js';
const sendData = () => {
const data = '来自兄弟组件的数据';
eventBus.emit('brotherEvent', data);
};
</script>
<!-- 接收数据的兄弟组件 -->
<template>
<div>
<p>{{ receivedData }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import eventBus from './eventBus.js';
const receivedData = ref('');
const handleEvent = (data) => {
receivedData.value = data;
};
onMounted(() => {
eventBus.on('brotherEvent', handleEvent);
});
onUnmounted(() => {
eventBus.off('brotherEvent', handleEvent);
});
</script>
使用状态管理库(如 Vuex 或 Pinia),可以将共享数据存储在一个集中的位置,兄弟组件可以从中获取和修改数据。
// stores/counter.js (Pinia 示例)
import { defineStore } from 'pinia';
export const useSharedStore = defineStore('shared', {
state: () => ({
sharedData: '初始共享数据'
}),
actions: {
updateSharedData(newData) {
this.sharedData = newData;
}
}
});
<!-- 发送数据的兄弟组件 -->
<template>
<div>
<button @click="updateData">更新共享数据</button>
</div>
</template>
<script setup>
import { useSharedStore } from '../stores/counter';
const sharedStore = useSharedStore();
const updateData = () => {
sharedStore.updateSharedData('新的共享数据');
};
</script>
<!-- 接收数据的兄弟组件 -->
<template>
<div>
<p>{{ sharedStore.sharedData }}</p>
</div>
</template>
<script setup>
import { useSharedStore } from '../stores/counter';
const sharedStore = useSharedStore();
</script>
localStorage
是浏览器提供的一种本地存储机制,可以在不同组件之间共享数据。一个组件将数据存储到 localStorage
中,另一个组件可以从 localStorage
中读取数据。
<!-- 发送数据的兄弟组件 -->
<template>
<div>
<button @click="saveDataToLocalStorage">保存数据到 localStorage</button>
</div>
</template>
<script setup>
const saveDataToLocalStorage = () => {
const data = '通过 localStorage 传递的数据';
localStorage.setItem('sharedData', data);
};
</script>
<!-- 接收数据的兄弟组件 -->
<template>
<div>
<p>{{ receivedData }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const receivedData = ref('');
onMounted(() => {
const data = localStorage.getItem('sharedData');
if (data) {
receivedData.value = data;
}
});
</script>
provide
和 inject
用于实现跨层级的组件数据传递。祖先组件通过 provide
提供数据,后代组件通过 inject
注入这些数据。
<!-- 祖先组件 -->
<template>
<div>
<ChildComponent />
</div>
</template>
<script setup>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const sharedData = ref('来自祖先组件的共享数据');
provide('sharedData', sharedData);
</script>
<!-- 后代组件(可以是多层嵌套) -->
<template>
<div>
<p>{{ injectedData }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
const injectedData = inject('sharedData');
</script>
和兄弟组件传值类似,使用状态管理库(如 Vuex 或 Pinia)可以方便地实现跨层级组件之间的数据共享和传递。所有组件都可以访问和修改存储在状态管理库中的数据。
在 Vue Router 中,可以通过路由参数或查询参数来传递数据。这种方式适用于在路由跳转时传递数据给目标组件。
// 路由配置
import { createRouter, createWebHistory } from 'vue-router';
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
const routes = [
{
path: '/componentB/:id',
name: 'ComponentB',
component: ComponentB
},
{
path: '/componentA',
name: 'ComponentA',
component: ComponentA
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
<!-- 发送数据的组件 ComponentA.vue -->
<template>
<div>
<router-link :to="{ name: 'ComponentB', params: { id: 123 } }">跳转到 ComponentB 并传参</router-link>
</div>
</template>
<script setup></script>
<!-- 接收数据的组件 ComponentB.vue -->
<template>
<div>
<p>接收到的参数 id: {{ $route.params.id }}</p>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
</script>
<!-- 发送数据的组件 ComponentA.vue -->
<template>
<div>
<router-link :to="{ name: 'ComponentB', query: { message: 'Hello from ComponentA' } }">跳转到 ComponentB 并传参</router-link>
</div>
</template>
<script setup></script>
<!-- 接收数据的组件 ComponentB.vue -->
<template>
<div>
<p>接收到的查询参数 message: {{ $route.query.message }}</p>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
</script>