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();