在Vue 3中,组件之间的通信可以通过多种方式进行,以下是一些常用的方法:
1. Props(父传子)
通过props,父组件可以向子组件传递数据。
// 父组件
<template>
<ChildComponent :user="user" />
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent,
},
data() {
return {
user: 'John Doe',
}
},
}
</script>
2. Emit(子传父)
子组件可以通过$emit事件向父组件发送消息。
// 子组件
<template>
<button @click="sendToParent">Send to Parent</button>
</template>
<script>
export default {
methods: {
sendToParent() {
this.$emit('sendMessage', 'Hello from child!')
},
},
}
</script>
// 父组件
<template>
<ChildComponent @sendMessage="handleMessage" />
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent,
},
methods: {
handleMessage(message) {
console.log(message)
},
},
}
</script>
3. Provide / Inject
Vue 3 提供了provide和inject来跨多个组件层次传递数据,而不必一层层传递props。
// 祖先组件
<script>
import {provide} from 'vue'
export default {
setup() {
const theme = 'dark'
provide('theme', theme)
},
}
</script>
// 后代组件
<script>
import {inject} from 'vue'
export default {
setup() {
const theme = inject('theme')
return {theme}
},
}
</script>
4. Event Bus(简单事件总线)
虽然Vue 3不再推荐使用Event Bus,但仍然可以通过创建一个简单的Vue实例作为事件总线来使用。
// event-bus.js
import {createApp} from 'vue'
const eventBus = createApp({})
export default eventBus
// 发送事件
import eventBus from './event-bus.js'
eventBus.emit('someEvent', 'Hello!')
// 监听事件
import eventBus from './event-bus.js'
eventBus.on('someEvent', message => {
console.log(message)
})
5. Vuex(状态管理)
对于大型应用,推荐使用Vuex来管理状态。
// store.js
import {createStore} from 'vuex'
export default createStore({
state: {
count: 0,
},
mutations: {
increment(state) {
state.count++
},
},
actions: {
increment({commit}) {
commit('increment')
},
},
})
// 组件中使用
<template>
<button @click="increment">Increment</button>
</template>
<script>
import {mapActions} from 'vuex'
export default {
methods: {
...mapActions(['increment']),
},
}
</script>
6. Refs 和 $parent/$children
通过ref属性可以获取子组件实例,从而调用子组件的方法或访问其数据。
// 父组件
<template>
<ChildComponent ref="child" />
</template>
<script>
import {ref} from 'vue'
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent,
},
setup() {
const child = ref(null)
// 在适当的时机调用子组件的方法
child.value.someMethod()
},
}
</script>
7. attrs 和 listeners
使用v-bind="$attrs"和v-on="$listeners"可以自动将父组件的属性和事件传递给子组件。
// 父组件
<template>
<ChildComponent :title="title" @click="handleClick" />
</template>
// 子组件
<template>
<div v-bind="$attrs" v-on="$listeners"></div>
</template>
8. Slots(插槽)
插槽是 Vue 中用于复合组件的一种内容分发机制,它允许你将组件的内容组合在一起。
默认插槽
<!-- 父组件 -->
<template>
<ChildComponent>
<p>This is some default content</p>
</ChildComponent>
</template>
<!-- 子组件 -->
<template>
<div>
<slot>Default slot content if no content is provided</slot>
</div>
</template>
如果父组件没有提供任何内容,那么子组件中定义的默认内容将会被渲染。
具名插槽
具名插槽允许你将内容分发到子组件的不同位置。
<!-- 父组件 -->
<template>
<ChildComponent>
<template v-slot:header>
<h1>This is a header</h1>
</template>
<template v-slot:default>
<p>This is the main content</p>
</template>
<template v-slot:footer>
<p>This is the footer</p>
</template>
</ChildComponent>
</template>
<!-- 子组件 -->
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
<!-- 默认插槽 -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
作用域插槽
作用域插槽允许你在父组件中访问子组件的数据。
<!-- 父组件 -->
<template>
<ChildComponent>
<template v-slot:default="slotProps">
<p>{{ slotProps.user.name }} - {{ slotProps.user.age }}</p>
</template>
</ChildComponent>
</template>
<!-- 子组件 -->
<template>
<div>
<slot :user="user"></slot>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: 'John Doe',
age: 30,
},
}
},
}
</script>
在上述例子中,ChildComponent 通过 slot 属性将 user 对象传递给了插槽,而父组件通过 v-slot:default="slotProps" 接收这个对象,并在插槽内容中使用它。
以上就是 Vue 3 中组件之间通信的各种方法,每种方法适用于不同的场景,你可以根据具体需求选择合适的方法。