在我的 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?潜在的解决方法?
应用程序.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>