Vue 3 通信方式
1 父子组件通信
1.1 Props
父组件通过 props
向子组件传递数据。
示例代码:
<!-- 父组件 -->
<template>
<Child :msg="msg" />
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';
const msg = ref('Hello from Parent');
</script>
<!-- 子组件 -->
<template>
<div>{{ msg }}</div>
</template>
<script setup>
defineProps({
msg: String
});
</script>
1.2 defineEmits
子组件通过 emit
触发事件向父组件发送消息。
示例代码:
<!-- 子组件 -->
<template>
<button @click="emitData">Emit Data</button>
</template>
<script setup>
const emit = defineEmits(['update']);
const emitData = () => {
emit('update', 'Data from Child');
};
</script>
<!-- 父组件 -->
<template>
<Child @update="handleUpdate" />
</template>
<script setup>
import Child from './Child.vue';
const handleUpdate = (data) => {
console.log(data); // 输出:Data from Child
};
</script>
1.3 $attrs
用于传递未被props
声明的属性。
示例代码:
<!-- 父组件 -->
<template>
<Child custom-attr="value" />
</template>
<!-- 子组件 -->
<template>
<div>{{ $attrs['custom-attr'] }}</div>
</template>
1.4 $ref + defineExpose
通过ref
引用子组件,并使用defineExpose
暴露子组件的方法
示例代码:
<!-- 子组件 -->
<script setup>
defineExpose({
someMethod() {
console.log('Method called');
}
});
</script>
<!-- 父组件 -->
<template>
<Child ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue';
import Child from './Child.vue';
const childRef = ref();
onMounted(() => {
childRef.value.someMethod(); // 输出:Method called
});
</script>
1.5 $parent
子组件通过$parent
直接访问父组件
示例代码:
<!-- 子组件 -->
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
console.log($parent.someData);
});
</script>
1.6 v-model
v-model
是 props
和 $emit
的语法糖,用于实现父组件和子组件之间的双向数据绑定
Vue3
支持多个 v-model
绑定,默认使用 modelValue
作为 prop
和 update:modelValue
作为事件。
示例代码:
<!-- 父组件 -->
<template>
<div>
<ChildComponent v-model="parentValue" />
<p>Parent value: {{ parentValue }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentValue = ref('Initial value');
</script>
<!-- 子组件 -->
<template>
<div>
<input v-model="modelValue" />
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
modelValue: String
});
const emits = defineEmits(['update:modelValue']);
const handleInput = (event) => {
emits('update:modelValue', event.target.value);
};
</script>
2 兄弟,跨层组件通信
2.1 全局事件总线(mitt)
使用事件总线(如mitt
或vue3-eventbus
)实现兄弟组件通信
示例代码:
npm install mitt
// eventBus.js
import mitt from 'mitt';
export const emitter = mitt();
<!-- 组件A -->
<script setup>
import { emitter } from './eventBus';
const sendData = () => {
emitter.emit('data', 'Hello from A');
};
</script>
<!-- 组件B -->
<script setup>
import { emitter } from './eventBus';
emitter.on('data', (data) => {
console.log(data); // 输出:Hello from A
});
</script>
示例代码2:
import { createApp } from 'vue';
import mitt from 'mitt';
import App from './App.vue';
const emitter = mitt();
const app = createApp(App);
app.config.globalProperties.emitter = emitter;
app.mount('#app');
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script setup>
const { emitter } = getCurrentInstance().appContext.config.globalProperties;
const sendMessage = () => {
emitter.emit('message', 'Hello from ComponentA');
};
</script>
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script setup>
const { emitter } = getCurrentInstance().appContext.config.globalProperties;
const sendMessage = () => {
emitter.emit('message', 'Hello from ComponentA');
};
</script>
2.2 provide/inject
祖先组件通过provide
提供数据,后代组件通过inject
注入
示例代码:
<!-- 祖先组件 -->
<template>
<ChildComponent />
</template>
<script setup>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const sharedData = ref('Shared Data');
provide('sharedData', sharedData);
</script>
<!-- 后代组件 -->
<template>
<p>{{ sharedData }}</p>
</template>
<script setup>
import { inject } from 'vue';
const sharedData = inject('sharedData');
</script>
2.3 Vuex
Vuex
是 Vue.js
的官方状态管理库,用于管理应用程序的状态。
示例代码:
import { createStore } from 'vuex';
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment(context) {
context.commit('increment');
}
},
getters: {
getCount(state) {
return state.count;
}
}
});
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
const count = computed(() => store.getters.getCount);
const increment = () => {
store.dispatch('increment');
};
</script>
2.4 Pinia
Pinia
是 Vue.js
的轻量级状态管理库,用于管理应用程序的状态。
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++;
}
}
});
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { useCounterStore } from '../store/counter';
const counterStore = useCounterStore();
const count = computed(() => counterStore.count);
const increment = () => {
counterStore.increment();
};
</script>
2.5 自定义 Hooks(Composables)
使用 Vue
3 的 Composition API
创建可复用的逻辑,用于组件之间的通信。
// useCounter.ts
import { ref } from 'vue';
export const useCounter = () => {
const count = ref(0);
const increment = () => {
count.value++;
};
return {
count,
increment
};
};
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { useCounter } from '../composables/useCounter';
const { count, increment } = useCounter();
</script>
3. 总结
通信方式 | 适用场景 | 注意事项 |
---|---|---|
Props/Events | 父子组件简单通信 | 避免深层次传递 |
v-model | 表单/组件双向绑定 | 支持多个绑定 |
Provide/Inject | 跨层级组件通信 | 需配合响应式数据 |
Pinia/Vuex | 全局状态管理 | 复杂项目推荐 |
自定义 Hooks | 逻辑复用 | 替代 mixins 的推荐方案 |
事件总线 | 任意组件间通信(小型项目) | 需手动维护事件监听/销毁 |