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 每一个实例。