@@ -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