From 522a97f8d6a1616206a56ccdf4c7a29a4a67a2df Mon Sep 17 00:00:00 2001 From: Hooray <304327508@qq.com> Date: Tue, 29 Jul 2025 00:57:27 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=20`useFaModal`=20=E5=92=8C?= =?UTF-8?q?=20`useFaDrawer`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/components/FaDrawer/index.ts | 71 ++++++++++------- src/ui/components/FaModal/index.ts | 76 +++++++++++-------- .../component_built_in_example/modal.vue | 31 +++++++- 3 files changed, 118 insertions(+), 60 deletions(-) diff --git a/src/ui/components/FaDrawer/index.ts b/src/ui/components/FaDrawer/index.ts index 58d33762..433ebf64 100644 --- a/src/ui/components/FaDrawer/index.ts +++ b/src/ui/components/FaDrawer/index.ts @@ -1,5 +1,5 @@ import type { Component, HTMLAttributes } from 'vue' -import { isVNode } from 'vue' +import { createVNode, isVNode, render } from 'vue' import Drawer from './index.vue' export interface DrawerProps { @@ -59,36 +59,49 @@ export function useFaDrawer() { const container = document.createElement('div') const visible = ref(false) const options = reactive({ ...initialOptions }) - const app = createApp({ - render() { - return h(Drawer, Object.assign({ - 'id': useId(), - 'modelValue': visible.value, - 'onUpdate:modelValue': (val: boolean) => { - visible.value = val - }, - }, options), { - default: () => { - if (typeof options.content === 'string') { - return options.content - } - else if (isVNode(options.content)) { - return options.content - } - else if (options.content) { - return h(options.content) - } - return null - }, - }) - }, - }) - // 继承主应用的上下文 const instance = getCurrentInstance() - if (instance && instance.appContext) { - Object.assign(app._context, instance.appContext) + let vnode: VNode | null = null + + const updateVNode = () => { + vnode = createVNode(Drawer, Object.assign({ + 'id': instance && instance.uid ? `FaDrawer-${instance.uid}` : undefined, + 'modelValue': visible.value, + 'onUpdate:modelValue': (val: boolean) => { + visible.value = val + }, + ...options, + }), { + default: () => { + if (typeof options.content === 'string') { + return options.content + } + else if (isVNode(options.content)) { + return options.content + } + else if (options.content) { + return h(options.content) + } + return null + }, + }) + // 继承主应用的上下文 + if (instance && instance.appContext) { + vnode.appContext = instance.appContext + } + render(vnode, container) } - app.mount(container) + + // 监听 visible 和 options 变化,自动重新渲染 + watch([visible, options], () => { + updateVNode() + }, { + immediate: true, + deep: true, + }) + + // 挂载到当前实例 + instance?.proxy?.$el?.appendChild(container) + const open = () => { visible.value = true } diff --git a/src/ui/components/FaModal/index.ts b/src/ui/components/FaModal/index.ts index 66ff8118..a662cf87 100644 --- a/src/ui/components/FaModal/index.ts +++ b/src/ui/components/FaModal/index.ts @@ -1,5 +1,5 @@ import type { Component, HTMLAttributes } from 'vue' -import { isVNode } from 'vue' +import { createVNode, isVNode, render } from 'vue' import Modal from './index.vue' export interface ModalProps { @@ -67,36 +67,49 @@ export function useFaModal() { const container = document.createElement('div') const visible = ref(false) const options = reactive({ ...initialOptions }) - const app = createApp({ - render() { - return h(Modal, Object.assign({ - 'id': useId(), - 'modelValue': visible.value, - 'onUpdate:modelValue': (val: boolean) => { - visible.value = val - }, - }, options), { - default: () => { - if (typeof options.content === 'string') { - return options.content - } - else if (isVNode(options.content)) { - return options.content - } - else if (options.content) { - return h(options.content) - } - return null - }, - }) - }, - }) - // 继承主应用的上下文 const instance = getCurrentInstance() - if (instance && instance.appContext) { - Object.assign(app._context, instance.appContext) + let vnode: VNode | null = null + + const updateVNode = () => { + vnode = createVNode(Modal, Object.assign({ + 'id': instance && instance.uid ? `FaModal-${instance.uid}` : undefined, + 'modelValue': visible.value, + 'onUpdate:modelValue': (val: boolean) => { + visible.value = val + }, + ...options, + }), { + default: () => { + if (typeof options.content === 'string') { + return options.content + } + else if (isVNode(options.content)) { + return options.content + } + else if (options.content) { + return h(options.content) + } + return null + }, + }) + // 继承主应用的上下文 + if (instance && instance.appContext) { + vnode.appContext = instance.appContext + } + render(vnode, container) } - app.mount(container) + + // 监听 visible 和 options 变化,自动重新渲染 + watch([visible, options], () => { + updateVNode() + }, { + immediate: true, + deep: true, + }) + + // 挂载到当前实例 + instance?.proxy?.$el?.appendChild(container) + const open = () => { visible.value = true } @@ -179,8 +192,11 @@ export function useFaModal() { contentClass: 'py-0 min-h-auto', footerClass: 'p-4', } - const { open } = create(Object.assign(defaultOptions, options)) + const { open, update } = create(Object.assign(defaultOptions, options)) open() + return { + update, + } } return { create, diff --git a/src/views/component_built_in_example/modal.vue b/src/views/component_built_in_example/modal.vue index 07aba535..a31f1c00 100644 --- a/src/views/component_built_in_example/modal.vue +++ b/src/views/component_built_in_example/modal.vue @@ -87,7 +87,33 @@ function showModalConfirm() { }, }) } - +function showModalDoubleConfirm() { + const { update } = useFaModal().confirm({ + title: '温馨提醒', + content: '这是 confirm 弹窗', + beforeClose: (action, done) => { + if (action === 'confirm') { + update({ + title: '二次确认', + content: '确定要关闭吗?', + confirmButtonText: '我确定', + cancelButtonText: '我取消', + beforeClose: (action) => { + if (action === 'confirm') { + done() + } + else { + done() + } + }, + }) + } + else { + done() + } + }, + }) +} function showModalPromiseConfirm() { useFaModal().confirm({ title: '温馨提醒', @@ -201,6 +227,9 @@ const { open: open2 } = useFaModal().create({ Confirm + + Double Confirm + Confirm with promise