diff --git a/example/components/demo-block/index.js b/example/components/demo-block/index.js index e7ea0e740..9872b213a 100644 --- a/example/components/demo-block/index.js +++ b/example/components/demo-block/index.js @@ -1,8 +1,9 @@ Component({ properties: { title: String, - padding: Boolean + padding: Boolean, + card: Boolean, }, - externalClasses: ['custom-class'] + externalClasses: ['custom-class'], }); diff --git a/example/components/demo-block/index.wxml b/example/components/demo-block/index.wxml index 07abe0bf0..d16b9a414 100644 --- a/example/components/demo-block/index.wxml +++ b/example/components/demo-block/index.wxml @@ -1,4 +1,7 @@ {{ title }} - + + + + diff --git a/example/components/demo-block/index.wxss b/example/components/demo-block/index.wxss index 183828c11..9a1d80860 100644 --- a/example/components/demo-block/index.wxss +++ b/example/components/demo-block/index.wxss @@ -2,10 +2,15 @@ .demo-block__title { margin: 0; + padding: 20px 15px 15px; + color: rgba(69, 90, 100, 0.6); font-weight: 400; font-size: 14px; - color: rgba(69,90,100,.6); - padding: 20px 15px 15px; +} + +.demo-block__card { + overflow: hidden; + border-radius: 8px; } .demo-block--padding { diff --git a/example/pages/dialog/index.js b/example/pages/dialog/index.js index 875defb52..40f45eb97 100644 --- a/example/pages/dialog/index.js +++ b/example/pages/dialog/index.js @@ -52,19 +52,23 @@ Page({ }, onClickAsyncClose() { - Dialog.confirm({ - title: '标题', - message, - asyncClose: true, - }) - .then(() => { + const beforeClose = (action) => + new Promise((resolve) => { setTimeout(() => { - Dialog.close(); + if (action === 'confirm') { + resolve(true); + } else { + // 拦截取消操作 + resolve(false); + } }, 1000); - }) - .catch(() => { - Dialog.close(); }); + + Dialog.confirm({ + title: '标题', + message, + beforeClose, + }); }, onClose() { diff --git a/example/pages/dialog/index.wxml b/example/pages/dialog/index.wxml index beb07d006..14442bf90 100644 --- a/example/pages/dialog/index.wxml +++ b/example/pages/dialog/index.wxml @@ -1,51 +1,35 @@ - - - 提示弹窗 - - - 提示弹窗(无标题) - + + + + - - - 提示弹窗 - - - 提示弹窗(无标题) - + + + - - - 确认弹窗 - + + - - - 异步关闭 - + + - - - 组件调用 - - - - - + + + diff --git a/packages/common/utils.ts b/packages/common/utils.ts index 633088dbe..954f41f01 100644 --- a/packages/common/utils.ts +++ b/packages/common/utils.ts @@ -1,4 +1,4 @@ -import { isNumber, isPlainObject } from './validator'; +import { isNumber, isPlainObject, isPromise } from './validator'; export function isDef(value: any): boolean { return value !== undefined && value !== null; @@ -96,3 +96,11 @@ export function getAllRect( } ); } + +export function toPromise(promiseLike: Promise | unknown) { + if (isPromise(promiseLike)) { + return promiseLike; + } + + return Promise.resolve(promiseLike); +} diff --git a/packages/dialog/README.md b/packages/dialog/README.md index e42bce50b..89ec90429 100644 --- a/packages/dialog/README.md +++ b/packages/dialog/README.md @@ -43,9 +43,26 @@ Dialog.alert({ }); ``` -### 圆角样式 +### 消息确认 + +用于确认消息,包含取消和确认按钮 + +```javascript +Dialog.confirm({ + title: '标题', + message: '弹窗内容', +}) + .then(() => { + // on confirm + }) + .catch(() => { + // on cancel + }); +``` + +### 圆角按钮风格 -样式为圆角风格。 +将 theme 选项设置为 `round-button` 可以展示圆角按钮风格的弹窗。 ```html @@ -70,46 +87,32 @@ Dialog.alert({ }); ``` -### 消息确认 - -用于确认消息,包含取消和确认按钮 - -```javascript -Dialog.confirm({ - title: '标题', - message: '弹窗内容', -}) - .then(() => { - // on confirm - }) - .catch(() => { - // on cancel - }); -``` - ### 异步关闭 -设置`asyncClose`属性开启异步关闭,开启后可以手动调用`Dialog.close`方法关闭弹窗 +通过 `beforeClose` 属性可以传入一个回调函数,在弹窗关闭前进行特定操作。 ```javascript +const beforeClose = (action) => new Promise((resolve) => { + setTimeout(() => { + if (action === 'confirm') { + resolve(true); + } else { + // 拦截取消操作 + resolve(false); + } + }, 1000); +}); + Dialog.confirm({ title: '标题', message: '弹窗内容' - asyncClose: true -}) - .then(() => { - setTimeout(() => { - Dialog.close(); - }, 1000); - }) - .catch(() => { - Dialog.close(); - }); + beforeClose +}); ``` ### 组件调用 -通过组件调用 Dialog 时,可以实现自定义弹窗内容、监听微信开放能力回调事件等功能,具体参考下例 +如果需要在弹窗内嵌入组件或其他自定义内容,可以使用组件调用的方式。 ```html boolean \| Promise_ | - | +| context | 选择器的选择范围,可以传入自定义组件的 this 作为上下文 | _object_ | 当前页面 | +| transition | 动画名称,可选值为`fade` `none` | _string_ | `scale` | +| confirmButtonOpenType | 确认按钮的微信开放能力,具体支持可参考 [微信官方文档](https://mp.weixin.qq.com/debug/wxadoc/dev/component/button.html) | _string_ | - | ### OpenType Options @@ -205,7 +209,7 @@ Page({ | --- | --- | --- | --- | | show | 是否显示弹窗 | _boolean_ | - | | title | 标题 | _string_ | - | -| width | 弹窗宽度,默认单位为`px` | _string \| number_ | `320px` | 1.0.0 | +| width | 弹窗宽度,默认单位为`px` | _string \| number_ | `320px` | | message | 文本内容,支持通过`\n`换行 | _string_ | - | | theme | 样式风格,可选值为`round-button` | _string_ | `default` | | message-align | 内容对齐方式,可选值为`left` `right` | _string_ | `center` | @@ -223,7 +227,8 @@ Page({ | close-on-click-overlay | 点击遮罩层时是否关闭弹窗 | _boolean_ | `false` | | use-slot | 是否使用自定义内容的插槽 | _boolean_ | `false` | | use-title-slot | 是否使用自定义标题的插槽 | _boolean_ | `false` | -| async-close | 是否异步关闭弹窗,开启后需要手动控制弹窗的关闭 | _boolean_ | `false` | +| async-close | 已废弃,将在 2.0.0 移除,请使用 `beforeClose` 属性代替 | _boolean_ | `false` | +| before-close | 关闭前的回调函数,返回 `false` 可阻止关闭,支持返回 Promise | _(action) => boolean \| Promise_ | - | | transition | 动画名称,可选值为`fade` | _string_ | `scale` | | confirm-button-open-type | 确认按钮的微信开放能力,具体支持可参考 [微信官方文档](https://mp.weixin.qq.com/debug/wxadoc/dev/component/button.html) | _string_ | - | diff --git a/packages/dialog/dialog.ts b/packages/dialog/dialog.ts index 5dd27f8c6..ff9d21ef4 100644 --- a/packages/dialog/dialog.ts +++ b/packages/dialog/dialog.ts @@ -1,4 +1,5 @@ let queue: WechatMiniprogram.Component.TrivialInstance[] = []; +export type Action = 'confirm' | 'cancel' | 'overlay'; interface DialogOptions { lang?: string; @@ -17,7 +18,11 @@ interface DialogOptions { className?: string; customStyle?: string; transition?: string; + /** + * @deprecated use beforeClose instead + */ asyncClose?: boolean; + beforeClose?: null | (() => Promise | void); businessId?: number; sessionFrom?: string; overlayStyle?: string; @@ -46,6 +51,7 @@ const defaultOptions: DialogOptions = { selector: '#van-dialog', className: '', asyncClose: false, + beforeClose: null, transition: 'scale', customStyle: '', messageAlign: '', @@ -81,8 +87,12 @@ const Dialog = (options: DialogOptions) => { if (dialog) { dialog.setData({ - onCancel: reject, - onConfirm: resolve, + callback: ( + action: Action, + instance: WechatMiniprogram.Component.TrivialInstance + ) => { + action === 'confirm' ? resolve(instance) : reject(instance); + }, ...options, }); diff --git a/packages/dialog/index.ts b/packages/dialog/index.ts index ea53003d1..bd27755d5 100644 --- a/packages/dialog/index.ts +++ b/packages/dialog/index.ts @@ -2,8 +2,8 @@ import { VantComponent } from '../common/component'; import { button } from '../mixins/button'; import { openType } from '../mixins/open-type'; import { GRAY, RED } from '../common/color'; - -type Action = 'confirm' | 'cancel' | 'overlay'; +import { toPromise } from '../common/utils'; +import type { Action } from './dialog'; VantComponent({ mixins: [button, openType], @@ -26,6 +26,7 @@ VantComponent({ customStyle: String, asyncClose: Boolean, messageAlign: String, + beforeClose: null, overlayStyle: String, useTitleSlot: Boolean, showCancelButton: Boolean, @@ -86,19 +87,16 @@ VantComponent({ this.onClose('overlay'); }, - handleAction(action: Action) { - if (this.data.asyncClose) { - this.setData({ - [`loading.${action}`]: true, - }); - } + close(action) { + this.setData({ show: false }); - this.onClose(action); - }, + wx.nextTick(() => { + this.$emit('close', action); - close() { - this.setData({ - show: false, + const { callback } = this.data; + if (callback) { + callback(action, this); + } }); }, @@ -111,20 +109,27 @@ VantComponent({ }); }, - onClose(action: Action) { - if (!this.data.asyncClose) { - this.close(); + handleAction(action: Action) { + this.$emit(action, { dialog: this }); + + const { asyncClose, beforeClose } = this.data; + if (!asyncClose && !beforeClose) { + this.close(action); + return; } - this.$emit('close', action); - // 把 dialog 实例传递出去,可以通过 stopLoading() 在外部关闭按钮的 loading - this.$emit(action, { dialog: this }); + this.setData({ + [`loading.${action}`]: true, + }); - const callback = this.data[ - action === 'confirm' ? 'onConfirm' : 'onCancel' - ]; - if (callback) { - callback(this); + if (beforeClose) { + toPromise(beforeClose(action)).then((value) => { + if (value) { + this.close(action); + } else { + this.stopLoading(); + } + }); } }, },