传送|可组合 - 在可组合内部使用组件并通过 Teleport 渲染

问题描述 投票:0回答:1

在我的 Vue3 应用程序上,我们有一个“BaseModal”组件,它可以执行模态框会执行的基本操作(打开、关闭等),但我们希望清理一些繁琐的代码。

我们希望通过可组合函数以编程方式将模式添加到 UI:

import { h, Teleport } from 'vue'
import BaseModal from '@shared/components/BaseModal.vue'

export default function useModal({ to = 'body' } = {}) {
  const show = (props = {}, slots = {}) => {
    h(Teleport, { to }, h(BaseModal, { ...props }, { ...slots }))
  }

  return { show }
}

潜在用途:

const { show } = useModal()

show({ title: 'Foobar' })

不幸的是,这根本不起作用。我是否错误地使用了 Teleport?潜在的解决方法?

vuejs3
1个回答
0
投票

VUE SFC 游乐场

  1. 渲染函数是返回 vnode 的函数。你什么也没返回
  2. 返回的Vnodes应该被挂载,没有父组件可以挂载
  3. 您应该手动安装
  4. 确保正确卸载对话框
  5. 返回组件公开的方法,以便客户端代码进一步操作它

应用程序.vue

<script setup>
parent.document.title = 'useModal()';
  
import {ref, reactive} from 'vue';
import useModal from './useModal';

window.console.log = msg => log.push(msg);
const log = reactive([]);

const { show } = useModal();

const foobar = ref();
const bazfoo = ref();

</script>

<template>
  <button @click="foobar = show({ title: 'Foobar' })">Show Foobar</button>
  <button @click="bazfoo = show({ title: 'Bazfoo' })">Show Bazfoo</button>
  <br/>
  <button @click="foobar?.close()">Close Foobar</button>
  <button @click="bazfoo?.close()">Close Bazfoo</button>
  <div>
    <div v-for="msg in log">{{ msg }}</div>
  </div>

</template>

useModal.js

import { h, render, ref, getCurrentInstance } from 'vue'
import BaseModal from './BaseModal.vue'

export default function useModal({ to = 'body' } = {}) {
  const self = getCurrentInstance();
  const exposed = ref();
  const show = (props = {}, slots = {}) => {
    const vnode = h(BaseModal, {...props, onClose(){
      exposed.value = null;
      render(null, document.querySelector(to));
    }}, {...slots});
    vnode.key = Math.random();
    vnode.appContext = self.appContext;
    render(vnode, document.querySelector(to));
    exposed.value = vnode.component.exposed;
    return exposed;
  }
  return { show }
}

BaseModal.vue

<script setup>
import {ref, onUnmounted} from 'vue';
const props = defineProps({
  title: String
});
const $dialog = ref();
onUnmounted(() => console.log(props.title + ' closed!'));
defineExpose({
  close: () => $dialog.value.close()
})
</script>

<template>
  <dialog open ref="$dialog">
    <h1>{{ title }}</h1>
    <button @click="$dialog.close()">Close</button>
  </dialog>
</template>
© www.soinside.com 2019 - 2024. All rights reserved.