默认情况下都应该使用 props & customs 进行通信。 兄弟或者说邻居之间无法直接通信,只能通过共同的parent组件间接通信。
但是假定如果若干组件之间有若干级 parent -> child -> grandchild -> great-grandchild … 的关系,parent 需要传递属性给 great-grandchild,需要处理 great-grandchild 发出的自定义事件,虽然中间的若干组件 child, grandchild 等与这些属性或事件并无关系,但仍然需要传递。
为了避免过多的层层传递,Vue 提供了 provide - inject 的通信模式以实现code 简化。
在parent 级的组件上 provide 需要的数据或者方法,然后这个组件的child, grandchild, great-grandchild 组件等都可以通过 inject 使用这些数据或方法,两个组件之间只要满足类似于parent - child 的关系就行,邻居关系的组件除外。
如果在所有的情况下都使用 props & custom events 进行组件之间的通信并不是错误的做法,使用 provide - inject 模式进行通信是一种可选做法,合理使用在某些情况下可以使代码更简洁。
举例:
- parent 组件 App.vue,
provide
对象数组topics
, 以及方法activateTopic
:
<template>
<div>
<knowledge-base></knowledge-base>
</div>
</template>
<script>
export default {
data() {
return {
topics: [
{
id: 'basics',
title: 'The Basics',
description: 'Core Vue basics you have to know',
fullText:
'Vue is a great framework',
},
],
activeTopic: null,
};
},
// 如果写成 provide: { topics: [{}] }
// 就需要copy一遍data里的topics数组,
// 这样会造成代码重复,所以改成 provide() {}
// 即方法的形式
provide() {
return {
topics: this.topics,
// not executing, just pointing to it
// selectTopic1 是任意指定的名称
selectTopic1: this.activateTopic,
}
},
methods: {
activateTopic(topicId) {
this.activeTopic = this.topics.find((topic) => topic.id === topicId);
},
},
};
</script>
- child 组件 knowledgeBase.vue, 由于自己并不需要使用其他组件的数据和方法,而且由于app 使用了 provide - inject 模式, 因此不需要传递数据或事件,没有
props
, 也没有emits
,十分简洁。反之,如果不使用 provide + inject ,代码不会这么简洁。
<template>
<section>
<h2>Select a Topic</h2>
<knowledge-grid></knowledge-grid>
</section>
</template>
<script>
export default {
};
</script>
- grandchild 组件 knowledgeGrid.vue,通过
inject
使用在App.vue 组件中提供的topics
数组。
<template>
<ul>
<knowledge-element
v-for="topic in topics"
:key="topic.id"
:id="topic.id"
:topic-name="topic.title"
:description="topic.description"
></knowledge-element>
</ul>
</template>
<script>
export default {
inject: ['topics'],
};
</script>
- great-grandchild 组件 KnowledgeElement.vue,使用inject,当 click 事件发生时,App.vue 中对应的方法会被调用。
<template>
<li>
<h3>{{ topicName }}</h3>
<p>{{ description }}</p>
<button @click="selectTopic1(id)">Learn More</button>
</li>
</template>
<script>
export default {
// selectTopic1 这里是随意定的一个名称
inject:['selectTopic1'],
props: ['id', 'topicName', 'description'],
};
</script>