Vue3 Composition API 调用组件独有的可重用反应值
Vue3 Composition API Reusable reactive values unique to calling component
运行 Vue 3.2.6 和 Vite 2.5.1
我一直在尝试使用新的合成 API 并尝试找出一些常见的用例,在这些用例中使用它来支持选项 API 是有意义的。我立即确定的一个很好的用例是模态窗口,即带有警告消息或对话或其他任何内容的小弹出窗口。
在我的旧应用程序中,我必须在调用模态的每个组件中创建模态打开逻辑,这会导致大量重复。使用 CompAPI,我尝试将逻辑提取到一个简单的 modal.ts
文件中,该文件导出 2 个东西,一个反应式 openModal
布尔值和一个 toggleModal
函数。效果很好!直到我的应用程序中有多个模式,也就是说,在这种情况下,它会同时打开每个模式,一个接一个地打开。
作为示例设置
modal.ts
import { ref } from "vue";
const openModal = ref(false);
const toggleModal = () => {
openModal.value = !openModal.value;
};
export { openModal, toggleModal };
App.vue
<template>
<Example1 />
<Example2 />
<Example3 />
</template>
Modal.vue
<template>
<div class="modal" @click.self.stop="sendClose">
<slot />
</div>
</template>
<script setup>
const emit = defineEmits(["closeModal"]);
const sendClose = () => {
emit("closeModal");
};
</script>
Example#.vue
请注意,每个组件都是具有相同布局的独立组件,唯一的区别是数量
<template>
<h1>Example 1 <span @click="toggleModal">Toggle</span></h1>
<teleport to="body">
<Modal v-if="openModal" @closeModal="toggleModal">
<h1>Modal 1</h1>
</Modal>
</teleport>
</template>
<script setup>
import { openModal, toggleModal } from "@/shared/modal";
import Modal from "@/components/Modal.vue";
</script>
单击 toggle
范围时发生的情况很明显(事后看来)。它切换 openModal
的值,这将同时打开所有 3 个模式,一个在另一个之上。如果您尝试实现嵌套模态,即一个模态中的逻辑将在该模态之上打开另一个模态,则问题会更糟。
我是不是误解了如何在这里使用 ref
?每个组件是否有可能拥有并跟踪自己的 openModal
版本?因为我在这里设置它的方式,它更像是一个全球商店,这对于这个特定的用例来说不是很好。
我想象的工作方式是每个组件都会导入反应性 openModal
值,并独立跟踪它。这样,当一个组件调用 toggleModal
时,它只会切换调用该函数的组件内部的值。
有没有办法通过组合 API 实现我最初的意图?我觉得答案很简单,但我真的想不通。
那是因为您没有正确导出您的合成,导致共享状态,因为您正在导出相同的函数和引用到所有组件。要解决您的问题,您应该将要在 modal.ts
中导出的任何内容包装在一个函数中,比如:
// Wrap in an exported function (you can also do a default export if you want)
export function modalComposition() {
const openModal = ref(false);
const toggleModal = () => {
openModal.value = !openModal.value;
};
return { openModal, toggleModal };
}
并且在你打算使用组合的每个组件中,简单地导入它,例如:
import { modalComposition } from "@/shared/modal";
import Modal from "@/components/Modal.vue";
// By invoking `modalComposition()`, you are no longer passing by reference
// And therefore there is no "shared state"
const { openModal, toggleModal } = modalComposition();
为什么这样做?
当您导出一个函数然后在每个组件的设置中调用它时,您确保通过执行该函数设置每个组件,returns 一个新的 ref
每一个实例。
运行 Vue 3.2.6 和 Vite 2.5.1
我一直在尝试使用新的合成 API 并尝试找出一些常见的用例,在这些用例中使用它来支持选项 API 是有意义的。我立即确定的一个很好的用例是模态窗口,即带有警告消息或对话或其他任何内容的小弹出窗口。
在我的旧应用程序中,我必须在调用模态的每个组件中创建模态打开逻辑,这会导致大量重复。使用 CompAPI,我尝试将逻辑提取到一个简单的 modal.ts
文件中,该文件导出 2 个东西,一个反应式 openModal
布尔值和一个 toggleModal
函数。效果很好!直到我的应用程序中有多个模式,也就是说,在这种情况下,它会同时打开每个模式,一个接一个地打开。
作为示例设置
modal.ts
import { ref } from "vue";
const openModal = ref(false);
const toggleModal = () => {
openModal.value = !openModal.value;
};
export { openModal, toggleModal };
App.vue
<template>
<Example1 />
<Example2 />
<Example3 />
</template>
Modal.vue
<template>
<div class="modal" @click.self.stop="sendClose">
<slot />
</div>
</template>
<script setup>
const emit = defineEmits(["closeModal"]);
const sendClose = () => {
emit("closeModal");
};
</script>
Example#.vue
请注意,每个组件都是具有相同布局的独立组件,唯一的区别是数量
<template>
<h1>Example 1 <span @click="toggleModal">Toggle</span></h1>
<teleport to="body">
<Modal v-if="openModal" @closeModal="toggleModal">
<h1>Modal 1</h1>
</Modal>
</teleport>
</template>
<script setup>
import { openModal, toggleModal } from "@/shared/modal";
import Modal from "@/components/Modal.vue";
</script>
单击 toggle
范围时发生的情况很明显(事后看来)。它切换 openModal
的值,这将同时打开所有 3 个模式,一个在另一个之上。如果您尝试实现嵌套模态,即一个模态中的逻辑将在该模态之上打开另一个模态,则问题会更糟。
我是不是误解了如何在这里使用 ref
?每个组件是否有可能拥有并跟踪自己的 openModal
版本?因为我在这里设置它的方式,它更像是一个全球商店,这对于这个特定的用例来说不是很好。
我想象的工作方式是每个组件都会导入反应性 openModal
值,并独立跟踪它。这样,当一个组件调用 toggleModal
时,它只会切换调用该函数的组件内部的值。
有没有办法通过组合 API 实现我最初的意图?我觉得答案很简单,但我真的想不通。
那是因为您没有正确导出您的合成,导致共享状态,因为您正在导出相同的函数和引用到所有组件。要解决您的问题,您应该将要在 modal.ts
中导出的任何内容包装在一个函数中,比如:
// Wrap in an exported function (you can also do a default export if you want)
export function modalComposition() {
const openModal = ref(false);
const toggleModal = () => {
openModal.value = !openModal.value;
};
return { openModal, toggleModal };
}
并且在你打算使用组合的每个组件中,简单地导入它,例如:
import { modalComposition } from "@/shared/modal";
import Modal from "@/components/Modal.vue";
// By invoking `modalComposition()`, you are no longer passing by reference
// And therefore there is no "shared state"
const { openModal, toggleModal } = modalComposition();
为什么这样做?
当您导出一个函数然后在每个组件的设置中调用它时,您确保通过执行该函数设置每个组件,returns 一个新的 ref
每一个实例。