小提琴:https://codesandbox.io/s/frosty-sound-xxn73s?file=/src/App.vue
我有两个
Vue
组件使用相同的 HappyDog.vue
组件:HumanJoe.vue
和 AlienBob.vue
。当其内部状态(苹果的数量)发生变化(随机增加或减少)时,HappyDog.vue
会发出事件。在更大的项目中,使用 HappyDog
的组件可以通过将反应数据作为 props 传递来改变其内部状态。
我希望能够在其他几个组件中使用相同的
HappyDog
组件,以便所有使用 HappyDog
的组件引用相同的组件,并具有相同数量的苹果。
App.vue:
<template>
<HumanJoe />
<AlienBob />
</template>
<script>
import HumanJoe from "./components/HumanJoe.vue";
import AlienBob from "./components/AlienBob.vue";
export default {
name: "App",
components: {
HumanJoe: HumanJoe,
AlienBob: AlienBob,
},
};
</script>
<style>
</style>
HappyDog.vue:
<template>
<div class="dog">
<b>Dog with {{ this.apples }} apples</b>
<div class="dog-apples">
<div class="apple" v-for="a in this.apples" :key="a"></div>
</div>
</div>
</template>
<script>
export default {
props: {},
data() {
return {
apples: 100,
};
},
created() {
this.interval = setInterval(() => this.changeApples(), 3000);
},
methods: {
changeApples() {
let add = 1 === Math.floor(Math.random() * 2) + 1; // [1, 2]
let random = 0;
if (add) {
random = Math.floor(Math.random() * 100) + 1; // [1, 100]
this.apples += random;
this.$emit("gain", this.apples);
} else {
random = Math.floor(Math.random() * 50) + 1; // [1, 50]
this.apples -= random;
if (this.apples < 0) {
this.apples = 0;
this.$emit("loss", this.apples);
}
}
},
},
};
</script>
<style scoped>
.dog {
width: 200px;
height: 200px;
background-color: orange;
font-weight: bold;
font-size: 200%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
overflow: scroll;
}
.dog-apples {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
margin: 5px;
}
.apple {
background-color: red;
border-radius: 50%;
width: 20px;
height: 20px;
margin: 5px;
}
</style>
以及使用
HappyDog.vue
的组件 - 为简单起见,它们几乎完全相同,但在更大的项目中,它们可以有自己的规则来决定如何对 HappyDog
发出的事件做出反应,以及可能的更改HappyDog
的状态:
HumanJoe.vue:
<template>
<div class="joe">
<b> Joe </b>
<HappyDog />
</div>
</template>
<script>
import HappyDog from "./HappyDog.vue";
export default {
name: "App",
components: {
HappyDog: HappyDog,
},
};
</script>
<style scoped>
.joe {
background-color: cyan;
display: flex;
flex-direction: column;
margin: 2em;
padding: 2em;
}
.joe b {
font-size: 200%;
}
</style>
AlienBob.vue:
<template>
<div class="bob">
<b> Bob </b>
<HappyDog />
</div>
</template>
<script>
import HappyDog from "./HappyDog.vue";
export default {
name: "App",
components: {
HappyDog: HappyDog,
},
};
</script>
<style scoped>
.bob {
background-color: lime;
display: flex;
flex-direction: column;
margin: 2em;
padding: 2em;
}
.bob b {
font-size: 200%;
}
</style>
我意识到,在这个简单的示例中,我可以通过传递一个将在
HappyDog
内部更新的反应式道具,在 HumanJoe
和 AlienBob
中制作不同的 App.vue
组件,并拥有相同数量的苹果,或者使用发出的事件来更新 apples
中的 App.vue
数据,该数据将作为道具传递给 HumanJoe
和 AlienBob
,但是,我真的希望它们都能够使用相同的 HappyDog
组件,如果这完全有可能。
我已经搜索过它,并找到了插槽和
is
,但我不确定这就是我要找的,因为我找不到共享相同组件的示例,而不是动态传递名称要创建的组件。
当您的 Vue 应用程序正在转换最终在具有 props 的组件之间产生严重耦合的内容时(如您的情况),最好使用状态管理。
状态管理有一个全局“存储”,您可以在其中定义状态(或多个状态)和操作。通过这种管理模型,您可以保存可在多个组件之间共享的“全局”数据。 在这里阅读更多相关信息。
一个例子是存储用户会话信息(即用户名、电子邮件等),或者在您的情况下,存储可以访问(查看)和更改(操作)的苹果数据(状态)。
Vuex 通常是首选,但它已经过渡到 Pinia - 所以我建议使用它。