在 Vue 3 中,组件传参的方式有多种,常见的方式包括
props、emit、v-model、provide/inject和ref/defineExpose,- 下面分别介绍:
方式一:props、emit
<!-- 父组件 -->
<script setup>
import ChildComponent from './ChildComponent.vue';
const message = 'Hello from parent';
const handleUpdate = (newMessage) => {
console.log(`子组件传递的参数为:${newMessage}`)
};
</script>
<template>
<ChildComponent :msg="message" @updateMessage="handleUpdate"/>
</template>
<!-- 子组件 -->
<script setup>
import { defineEmits } from 'vue';
defineProps({
msg: String
});
const emit = defineEmits(['updateMessage']);
const sendMessage = () => {
emit('updateMessage', 'Hello from child');
};
</script>
<template>
<p>{{ msg }}</p>
<button @click="sendMessage">发送消息</button>
</template>
方式二:provide/inject
provide 和 inject 允许祖先组件向所有子孙组件传递数据,而不需要通过每一层组件手动传递。
//1. 在`父组件/根组件`中定义`provide`,**提供数据**。
<script setup>
import { ref, provide } from 'vue';
const name = ref('sam');
provide('name', name)
</script>
//2. 在`子组件/孙子组件`中使用`inject`,**注入数据**。
<script setup>
import { inject } from 'vue';
const name = inject('name');
console.log('name:', name.value); //输出name:sam
</script>
方式三:兄弟组件通信 (Mitt)
对于兄弟组件之间的通信,我们可以使用第三方库 mitt 来实现一个简单的事件总线。
首先,安装 mitt:
npm install --save mitt
然后,在 main.js 中全局配置:
import { createApp } from 'vue'
import mitt from 'mitt'
import App from './App.vue'
const app = createApp(App)
app.config.globalProperties.$bus = mitt()
app.mount('#app')
「发送事件的组件:」
<script setup>
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
const sendMessage = () => {
proxy.$bus.emit('myEvent', 'Hello world');
}
</script>
「接收事件的组件:」
<script setup>
import { onMounted, getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
onMounted(() => {
proxy.$bus.on('myEvent', (message) => {
console.log(message) // 输出: "Hello world"
})
})
</script>
方式四:透传 Attributes ($attrs)
$attrs 包含了父组件传递给子组件的所有属性,除了那些已经被 props 或 emits 声明的。
//父组件
<template>
<child name="小明" age="18" hobby="篮球"></child>
</template>
//子组件
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
console.log(attrs) // { age: "18", hobby: "篮球" }
</script>
方式五:模板引用 (Refs)
通过 ref,父组件可以直接访问子组件的属性和方法。
//父组件
<template>
<child ref="childRef"></child>
<button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childRef = ref(null)
const callChildMethod = () => {
childRef.value.someMethod()
}
</script>
//子组件
<script setup>
import { defineExpose } from 'vue'
const someMethod = () => {
console.log('子组件方法被调用了')
}
defineExpose({
someMethod,
})
</script>
方式六:双向绑定 (v-model)
v-model 提供了一种简洁的方式来实现父子组件之间的双向数据绑定。
//父组件
<template>
<child v-model:name="name"></child>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const name = ref('小明')
</script>
//子组件
<template>
<input :value="name" @input="updateName" />
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps(['name'])
const emit = defineEmits(['update:name'])
const updateName = (e) => {
emit('update:name', e.target.value)
}
</script>
方式七:状态管理
- Pinia 是新一代的 Vue 状态管理库,提供更简单的 API 和更好的 TypeScript 支持
- Vuex 是 Vue 的官方状态管理库,适用于大型应用。
方式八:浏览器存储
localStorage 和 sessionStorage 可以用于在不同页面或组件之间共享数据。
方式九:全局属性
// main.js
const app = createApp(App)
app.config.globalProperties.$http = axios
// 在组件中使用
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
proxy.$http.get('/api/data')