From 9d27335e2a1d3bb1512d9306ab05a05b08fc7889 Mon Sep 17 00:00:00 2001 From: fennghuang <89014758+fennghuang@users.noreply.github.com> Date: Mon, 6 Nov 2023 03:33:07 +0000 Subject: [PATCH 1/4] =?UTF-8?q?fix(dialog):=20=E4=BF=AE=E6=AD=A3=20destroy?= =?UTF-8?q?OnClose=20=E5=B1=9E=E6=80=A7=E4=BC=A0=E9=80=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dialog/dialog.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dialog/dialog.vue b/src/dialog/dialog.vue index 92faf9cd4..435bed437 100644 --- a/src/dialog/dialog.vue +++ b/src/dialog/dialog.vue @@ -5,6 +5,7 @@ :show-overlay="showOverlay" :overlay-props="overlayProps" :prevent-scroll-through="preventScrollThrough" + :destroy-on-close="destroyOnClose" @close="handleOverlayClick" >
From 4ee122b788c3c485effc12471d75a7567bd6baab Mon Sep 17 00:00:00 2001 From: fennghuang <89014758+fennghuang@users.noreply.github.com> Date: Tue, 7 Nov 2023 08:30:04 +0000 Subject: [PATCH 2/4] =?UTF-8?q?fix(dialog):=20=E4=BF=AE=E6=AD=A3=20dialog?= =?UTF-8?q?=20=E5=AE=9E=E4=BE=8B=E7=94=9F=E6=88=90=E5=92=8C=E8=BF=94?= =?UTF-8?q?=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dialog/dialog.vue | 10 +++- src/dialog/index.ts | 123 +++++++++++++++++++++++------------------- src/dialog/props.ts | 2 + src/dialog/type.ts | 4 ++ 4 files changed, 83 insertions(+), 56 deletions(-) diff --git a/src/dialog/dialog.vue b/src/dialog/dialog.vue index 435bed437..f45b1b34f 100644 --- a/src/dialog/dialog.vue +++ b/src/dialog/dialog.vue @@ -7,8 +7,9 @@ :prevent-scroll-through="preventScrollThrough" :destroy-on-close="destroyOnClose" @close="handleOverlayClick" + @closed="handleClosed" > -
+
@@ -69,7 +70,7 @@ export default defineComponent({ name, components: { TPopup, TNode, TButton, CloseIcon }, props: DialogProps, - emits: ['update:visible', 'confirm', 'overlay-click', 'cancel', 'close'], + emits: ['update:visible', 'confirm', 'overlay-click', 'cancel', 'close', 'closed'], setup(props, context) { const internalInstance = getCurrentInstance(); const contentNode = computed(() => renderContent(internalInstance, 'default', 'content')); @@ -105,6 +106,10 @@ export default defineComponent({ context.emit('close', { e, trigger: 'close-btn' }); }; + const handleClosed = () => { + context.emit('closed'); + }; + const handleConfirm = (e: MouseEvent) => { context.emit('update:visible', false); context.emit?.('confirm', { e }); @@ -147,6 +152,7 @@ export default defineComponent({ cancelBtnProps, actionsBtnProps, handleClose, + handleClosed, handleConfirm, handleCancel, handleOverlayClick, diff --git a/src/dialog/index.ts b/src/dialog/index.ts index 746795d0a..99320f354 100644 --- a/src/dialog/index.ts +++ b/src/dialog/index.ts @@ -1,8 +1,8 @@ -import { createApp, defineComponent, h, VNode, App, ref, DefineComponent, nextTick } from 'vue'; +import { createApp, h, App, ref, nextTick, reactive } from 'vue'; import Dialog from './dialog.vue'; import { WithInstallType } from '../shared'; -import { DialogCloseContext, TdDialogProps } from './type'; +import { DialogCloseContext, TdDialogProps, DialogInstance } from './type'; import './style'; @@ -20,73 +20,88 @@ export const DialogPropsDefault = { closeOnOverlayClick: false, }; -let instance: DefineComponent; +const propsFn = ['onConfirm', 'onCancel', 'onOverlayClick', 'onClose', 'onClosed'] as const; +type DialogPropsFnName = (typeof propsFn)[number]; -function create(props: Partial | string): DefineComponent { - const visible = ref(false); +function create(options: Partial | string): DialogInstance { const root = document.createElement('div'); document.body.appendChild(root); + const props = ref>({}); const propsObject = { ...DialogPropsDefault, - ...(typeof props === 'string' ? { content: props } : props), + ...(typeof options === 'string' ? { content: options } : options), }; - if (instance) { - instance.clear(); - // instance = null; + function callFn(fnType: DialogPropsFnName, context?: T): void { + const fn = props.value[fnType] || propsObject[fnType]; + typeof fn === 'function' && fn(context as any); } - // eslint-disable-next-line vue/one-component-per-file - instance = defineComponent({ - render: (): VNode => - // @ts-ignore - h(Dialog, { - ...propsObject, - visible: visible.value, - onConfirm: (context: { e: MouseEvent }) => { - if (typeof propsObject.onConfirm === 'function') { - propsObject.onConfirm(context); - } - visible.value = false; - }, - onCancel: (context: { e: MouseEvent }) => { - if (typeof propsObject.onCancel === 'function') { - propsObject.onCancel(context); - } - visible.value = false; - }, - onOverlayClick: (context: { e: MouseEvent }) => { - if (typeof propsObject.onOverlayClick === 'function') { - propsObject.onOverlayClick(context); - } - visible.value = false; - }, - onClose: (context: DialogCloseContext) => { - root.remove(); - if (typeof propsObject.onClose === 'function') { - propsObject.onClose(context); - } - }, - }), + const params = reactive({ + ...propsObject, + onConfirm: (context: { e: MouseEvent }) => { + callFn('onConfirm', context); + params.visible = false; + }, + onCancel: (context: { e: MouseEvent }) => { + callFn('onCancel', context); + params.visible = false; + }, + onOverlayClick: (context: { e: MouseEvent }) => { + callFn('onOverlayClick', context); + params.visible = false; + }, + onClose: (context: DialogCloseContext) => { + callFn('onClose', context); + root.remove(); + }, + onClosed: () => { + callFn('onClosed'); + // 卸载创建的app + params.destroyOnClose && app.unmount(); + }, }); - instance.clear = () => { - root.remove(); + const app = createApp(() => h(Dialog, params)); + app.mount(root); + + const handler = { + destroy() { + params.destroyOnClose = true; + nextTick(() => { + params.visible = false; + root.remove(); + }); + }, + hide() { + params.visible = false; + }, + show() { + params.visible = true; + }, + update(options: Partial | string) { + if (typeof options === 'string') { + params.content = options; + } else { + for (const key in options) { + if (propsFn.includes(key as DialogPropsFnName)) { + props.value[key] = options[key]; + } else { + params[key] = options[key]; + } + } + } + }, }; - // eslint-disable-next-line vue/one-component-per-file - createApp(instance).mount(root); - - nextTick(() => { - visible.value = true; - }); + nextTick(() => (params.visible = true)); - return instance; + return handler; } (['show', 'alert', 'confirm'] as DialogType[]).forEach((type: DialogType): void => { - Dialog[type] = (options: Partial | string) => { + Dialog[type] = (options: Partial | string): DialogInstance => { let props: any = { content: '' }; if (typeof options === 'string') { @@ -113,11 +128,11 @@ Dialog.install = (app: App, name = '') => { type DialogApi = { /** 通用对话框 */ - show: (options: Partial | string) => void; + show: (options: Partial | string) => DialogInstance; /** 基础对话框 */ - alert: (options: Partial | string) => void; + alert: (options: Partial | string) => DialogInstance; /** 选择对话框 */ - confirm: (options: Partial | string) => void; + confirm: (options: Partial | string) => DialogInstance; }; export const DialogPlugin: WithInstallType & DialogApi = Dialog as any; diff --git a/src/dialog/props.ts b/src/dialog/props.ts index 6b6d3f377..ce73affc7 100644 --- a/src/dialog/props.ts +++ b/src/dialog/props.ts @@ -78,6 +78,8 @@ export default { onCancel: Function as PropType, /** 关闭事件,点击 取消按钮 或 点击蒙层 时触发 */ onClose: Function as PropType, + /** 组件关闭且动画结束后执行 */ + onClosed: Function as PropType, /** 如果“确认”按钮存在,则点击“确认”按钮时触发 */ onConfirm: Function as PropType, /** 如果蒙层存在,点击蒙层时触发 */ diff --git a/src/dialog/type.ts b/src/dialog/type.ts index 5bfd034c8..29ea94b55 100644 --- a/src/dialog/type.ts +++ b/src/dialog/type.ts @@ -77,6 +77,10 @@ export interface TdDialogProps { * 关闭事件,点击 取消按钮 或 点击蒙层 时触发 */ onClose?: (context: DialogCloseContext) => void; + /** + * 组件关闭且动画结束后执行 + */ + onClosed?: () => void; /** * 如果“确认”按钮存在,则点击“确认”按钮时触发 */ From a6c6ff6860c6e16acb3f2c0d2bd4726eea9748fe Mon Sep 17 00:00:00 2001 From: fennghuang <89014758+fennghuang@users.noreply.github.com> Date: Tue, 7 Nov 2023 08:59:22 +0000 Subject: [PATCH 3/4] =?UTF-8?q?fix(dialog):=20=E6=9B=B4=E6=96=B0test-snap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__test__/__snapshots__/demo.test.jsx.snap | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/dialog/__test__/__snapshots__/demo.test.jsx.snap b/src/dialog/__test__/__snapshots__/demo.test.jsx.snap index 0636c7686..489c010d4 100644 --- a/src/dialog/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/dialog/__test__/__snapshots__/demo.test.jsx.snap @@ -40,7 +40,6 @@ exports[`Dialog > Dialog confirmVue demo works fine 1`] = `
@@ -146,7 +145,6 @@ exports[`Dialog > Dialog confirmVue demo works fine 1`] = `
@@ -254,7 +252,6 @@ exports[`Dialog > Dialog feedbackVue demo works fine 1`] = `
@@ -347,7 +344,6 @@ exports[`Dialog > Dialog feedbackVue demo works fine 1`] = `
@@ -436,7 +432,6 @@ exports[`Dialog > Dialog feedbackVue demo works fine 1`] = `
@@ -539,7 +534,6 @@ exports[`Dialog > Dialog imageDialogVue demo works fine 1`] = `
Dialog imageDialogVue demo works fine 1`] = `
@@ -850,7 +843,6 @@ exports[`Dialog > Dialog inputVue demo works fine 1`] = `
@@ -999,7 +991,6 @@ exports[`Dialog > Dialog inputVue demo works fine 1`] = `
@@ -1187,7 +1178,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -1280,7 +1270,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -1369,7 +1358,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -1483,7 +1471,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -1589,7 +1576,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -1712,7 +1698,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -1861,7 +1846,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -2033,7 +2017,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
Dialog mobileVue demo works fine 1`] = `
@@ -2359,7 +2341,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -2465,7 +2446,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -2571,7 +2551,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -2677,7 +2656,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -2800,7 +2778,6 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
@@ -2968,7 +2945,6 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
@@ -3074,7 +3050,6 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
@@ -3180,7 +3155,6 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
@@ -3286,7 +3260,6 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
@@ -3409,7 +3382,6 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
From 17769eb8589380e5b5256a9e6f01e47198b8cf9b Mon Sep 17 00:00:00 2001 From: fennghuang <89014758+fennghuang@users.noreply.github.com> Date: Wed, 22 Nov 2023 07:07:24 +0000 Subject: [PATCH 4/4] =?UTF-8?q?fix(dialog):=20=E4=BF=AE=E6=AD=A3=20dialog?= =?UTF-8?q?=20=E5=AE=9E=E4=BE=8B=E7=94=9F=E6=88=90=E5=92=8C=E8=BF=94?= =?UTF-8?q?=E5=9B=9E-=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dialog/dialog.en-US.md | 1 + src/dialog/dialog.md | 1 + 2 files changed, 2 insertions(+) diff --git a/src/dialog/dialog.en-US.md b/src/dialog/dialog.en-US.md index 4748ac3e8..639de437e 100644 --- a/src/dialog/dialog.en-US.md +++ b/src/dialog/dialog.en-US.md @@ -22,6 +22,7 @@ width | String / Number | - | \- | N zIndex | Number | - | \- | N onCancel | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onClose | Function | | Typescript:`(context: DialogCloseContext) => void`
[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/dialog/type.ts)。
`type DialogEventSource = 'cancel' \| 'overlay'`

`interface DialogCloseContext { trigger: DialogEventSource; e: MouseEvent }`
| N +onClosed | Function | | Typescript:`() => void`
| N onConfirm | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onOverlayClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N diff --git a/src/dialog/dialog.md b/src/dialog/dialog.md index 2e563b7a2..71bcc6c1f 100644 --- a/src/dialog/dialog.md +++ b/src/dialog/dialog.md @@ -22,6 +22,7 @@ width | String / Number | - | 对话框宽度,示例:320, '500px', '80%' | N zIndex | Number | - | 对话框层级,Web 侧样式默认为 2500,移动端和小程序样式默认为 1500 | N onCancel | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
如果“取消”按钮存在,则点击“取消”按钮时触发,同时触发关闭事件 | N onClose | Function | | TS 类型:`(context: DialogCloseContext) => void`
关闭事件,点击 取消按钮 或 点击蒙层 时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/dialog/type.ts)。
`type DialogEventSource = 'cancel' \| 'overlay'`

`interface DialogCloseContext { trigger: DialogEventSource; e: MouseEvent }`
| N +onClosed | Function | | TS 类型:`() => void`
组件关闭且动画结束后执行。 | N onConfirm | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
如果“确认”按钮存在,则点击“确认”按钮时触发 | N onOverlayClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
如果蒙层存在,点击蒙层时触发 | N