diff --git a/docs/markdown/migrate-from-v2.zh-CN.md b/docs/markdown/migrate-from-v2.zh-CN.md
index 0194738a6..59fa52f91 100644
--- a/docs/markdown/migrate-from-v2.zh-CN.md
+++ b/docs/markdown/migrate-from-v2.zh-CN.md
@@ -171,6 +171,10 @@ Vue 3.0 中增加了 `Teleport` 组件,提供将组件渲染到任意 DOM 位
- 蓝色按钮对应的类型由 `info` 调整为 `primary`
- 绿色按钮对应的类型由 `primary` 调整为 `success`
+#### Dialog
+
+- `before-close` 属性用法调整,不再传入 done 函数,而是通过返回 Promise 来控制
+
#### Picker
- 移除 change 事件的第一个参数(picker 实例)
diff --git a/src/dialog/Dialog.js b/src/dialog/Dialog.js
index 379795117..d54f9f817 100644
--- a/src/dialog/Dialog.js
+++ b/src/dialog/Dialog.js
@@ -1,6 +1,7 @@
import { reactive } from 'vue';
// Utils
+import { callInterceptor } from '../utils/interceptor';
import { createNamespace, addUnit, pick } from '../utils';
import { BORDER_TOP, BORDER_LEFT } from '../utils/constant';
@@ -82,11 +83,16 @@ export default createComponent({
if (props.beforeClose) {
loading[action] = true;
- props.beforeClose(action, (result) => {
- if (result !== false && loading[action]) {
+ callInterceptor({
+ interceptor: props.beforeClose,
+ args: [action],
+ done() {
close(action);
- }
- loading[action] = false;
+ loading[action] = false;
+ },
+ canceled() {
+ loading[action] = false;
+ },
});
} else {
close(action);
diff --git a/src/dialog/README.md b/src/dialog/README.md
index 77f0d2016..5e6cfe6e4 100644
--- a/src/dialog/README.md
+++ b/src/dialog/README.md
@@ -72,13 +72,12 @@ Dialog.alert({
### Asnyc Close
```js
-function beforeClose(action, done) {
- if (action === 'confirm') {
- setTimeout(done, 1000);
- } else {
- done();
- }
-}
+const beforeClose = (action, done) =>
+ new Promsie((resolve) => {
+ setTimeout(() => {
+ resolve(action === 'confirm');
+ }, 1000);
+ });
Dialog.confirm({
title: 'Title',
@@ -185,7 +184,7 @@ export default {
| lazy-render | Whether to lazy render util appeared | _boolean_ | `true` |
| lock-scroll | Whether to lock background scroll | _boolean_ | `true` |
| allow-html `v2.8.7` | Whether to allow HTML rendering in message | _boolean_ | `true` |
-| before-close | Callback before close,
call done() to close dialog,
call done(false) to cancel loading | (action: string, done: Function) => void | - |
+| before-close | Callback before close | _(action) => boolean \| Promise_ | - |
| transition | Transition, equivalent to `name` prop of [transtion](https://vuejs.org/v2/api/#transition) | _string_ | - |
| teleport | Return the mount node for Dialog | _string \| Element_ | - |
diff --git a/src/dialog/README.zh-CN.md b/src/dialog/README.zh-CN.md
index ac64ce6d2..c2e7a10a4 100644
--- a/src/dialog/README.zh-CN.md
+++ b/src/dialog/README.zh-CN.md
@@ -100,13 +100,17 @@ Dialog.alert({
通过 `beforeClose` 属性可以传入一个回调函数,在弹窗关闭前进行特定操作。
```js
-function beforeClose(action, done) {
- if (action === 'confirm') {
- setTimeout(done, 1000);
- } else {
- done();
- }
-}
+const beforeClose = (action, done) =>
+ new Promsie((resolve) => {
+ setTimeout(() => {
+ if (action === 'confirm') {
+ resolve(true);
+ } else {
+ // 拦截取消操作
+ resolve(false);
+ }
+ }, 1000);
+ });
Dialog.confirm({
title: '标题',
@@ -217,7 +221,7 @@ export default {
| lazy-render | 是否在显示弹层时才渲染节点 | _boolean_ | `true` |
| lock-scroll | 是否锁定背景滚动 | _boolean_ | `true` |
| allow-html `v2.8.7` | 是否允许 message 内容中渲染 HTML | _boolean_ | `true` |
-| before-close | 关闭前的回调函数,
调用 done() 后关闭弹窗,
调用 done(false) 阻止弹窗关闭 | _(action, done) => void_ | - |
+| before-close | 关闭前的回调函数,返回 `false` 可阻止关闭,支持返回 Promise | _(action) => boolean \| Promise_ | - |
| transition | 动画类名,等价于 [transtion](https://cn.vuejs.org/v2/api/index.html#transition) 的`name`属性 | _string_ | - |
| teleport | 指定挂载的节点,[用法示例](#/zh-CN/popup#zhi-ding-gua-zai-wei-zhi) | _string \| Element_ | - |
diff --git a/src/dialog/demo/index.vue b/src/dialog/demo/index.vue
index d25ab4308..ff0e2efa2 100644
--- a/src/dialog/demo/index.vue
+++ b/src/dialog/demo/index.vue
@@ -11,8 +11,8 @@
-
-
+
+
@@ -36,7 +36,7 @@ export default {
alert1: '提示弹窗',
alert2: '提示弹窗(无标题)',
confirm: '确认弹窗',
- asyncClose: '异步关闭',
+ beforeClose: '异步关闭',
roundButton: '圆角按钮样式',
componentCall: '组件调用',
content: '代码是写出来给人看的,附带能在机器上运行',
@@ -45,7 +45,7 @@ export default {
alert1: 'Alert',
alert2: 'Alert without title',
confirm: 'Confirm dialog',
- asyncClose: 'Async Close',
+ beforeClose: 'Async Close',
roundButton: 'Round Button Style',
componentCall: 'Component Call',
},
@@ -95,14 +95,11 @@ export default {
});
},
- onClickAsyncClose() {
- function beforeClose(action, done) {
- if (action === 'confirm') {
- setTimeout(done, 1000);
- } else {
- done();
- }
- }
+ onClickBeforeClose() {
+ const beforeClose = (action) =>
+ new Promise((resolve) => {
+ setTimeout(() => resolve(action === 'confirm'), 1000);
+ });
this.$dialog.confirm({
title: this.t('title'),
diff --git a/src/utils/interceptor.ts b/src/utils/interceptor.ts
index 96cb63481..fa0af4f9b 100644
--- a/src/utils/interceptor.ts
+++ b/src/utils/interceptor.ts
@@ -2,10 +2,11 @@ import { isPromise, noop } from '.';
export function callInterceptor(options: {
interceptor?: (...args: any[]) => Promise | boolean;
- done: () => void;
args: any[];
+ done: () => void;
+ canceled?: () => void;
}) {
- const { interceptor, args, done } = options;
+ const { interceptor, args, done, canceled } = options;
if (interceptor) {
const returnVal = interceptor(...args);
@@ -15,11 +16,15 @@ export function callInterceptor(options: {
.then((value) => {
if (value) {
done();
+ } else if (canceled) {
+ canceled();
}
})
.catch(noop);
} else if (returnVal) {
done();
+ } else if (canceled) {
+ canceled();
}
} else {
done();