From f3ff931ebf5f007d604f8e46bfd83da60f7e80a4 Mon Sep 17 00:00:00 2001 From: chenjiahan Date: Sun, 26 Jul 2020 16:35:08 +0800 Subject: [PATCH] feat: migrate Dialog component --- breaking-changes.md | 1 + components.js | 1 + src/dialog/Dialog.js | 61 +++++----- src/dialog/README.md | 4 +- src/dialog/README.zh-CN.md | 220 ------------------------------------- src/dialog/demo/index.vue | 2 +- src/dialog/index.js | 76 +++++++------ src/dialog/index.less | 4 +- vant.config.js | 16 +-- 9 files changed, 86 insertions(+), 299 deletions(-) diff --git a/breaking-changes.md b/breaking-changes.md index a5d59d872..e2350b66d 100644 --- a/breaking-changes.md +++ b/breaking-changes.md @@ -7,6 +7,7 @@ - Tabs: `v-model` 重命名为 `v-model:active` - Popup: `v-model` 重命名为 `v-model:show` - Circle: `v-model` 重命名为 `v-model:currentRate` +- Dialog: `v-model` 重命名为 `v-model:show` - ShareSheet: `v-model` 重命名为 `v-model:show` - ActionSheet: `v-model` 重命名为 `v-model:show` - List: `v-model` 重命名为 `v-model:loading`,`error.sync` 重命名为 `v-model:error` diff --git a/components.js b/components.js index 5169725a9..caa3f4ba0 100644 --- a/components.js +++ b/components.js @@ -44,4 +44,5 @@ module.exports = [ 'tabs', 'sticky', 'picker', + 'dialog', ]; diff --git a/src/dialog/Dialog.js b/src/dialog/Dialog.js index 815dad25c..85e84a27a 100644 --- a/src/dialog/Dialog.js +++ b/src/dialog/Dialog.js @@ -1,19 +1,19 @@ import { createNamespace, addUnit } from '../utils'; import { BORDER_TOP, BORDER_LEFT } from '../utils/constant'; -import { PopupMixin } from '../mixins/popup'; +import Popup from '../popup'; import Button from '../button'; const [createComponent, bem, t] = createNamespace('dialog'); export default createComponent({ - mixins: [PopupMixin()], - props: { + show: Boolean, title: String, width: [Number, String], message: String, className: null, callback: Function, + lazyRender: Boolean, beforeClose: Function, messageAlign: String, cancelButtonText: String, @@ -65,7 +65,7 @@ export default createComponent({ this.$emit(action); // show not trigger close event when hidden - if (!this.value) { + if (!this.show) { return; } @@ -85,7 +85,7 @@ export default createComponent({ }, onClose(action) { - this.close(); + this.$emit('update:show', false); if (this.callback) { this.callback(action); @@ -133,9 +133,9 @@ export default createComponent({ ); }, - genContent(hasTitle, messageSlot) { - if (messageSlot) { - return
{messageSlot}
; + genContent(hasTitle) { + if (this.$slots.default) { + return
{this.$slots.default()}
; } const { message, messageAlign } = this; @@ -145,9 +145,7 @@ export default createComponent({ 'has-title': hasTitle, [messageAlign]: messageAlign, }), - domProps: { - [this.allowHtml ? 'innerHTML' : 'textContent']: message, - }, + [this.allowHtml ? 'innerHTML' : 'textContent']: message, }; return ( @@ -160,37 +158,32 @@ export default createComponent({ }, render() { - if (!this.shouldRender) { - return; - } - const { message } = this; - const messageSlot = this.slots(); - const title = this.slots('title') || this.title; + const title = this.$slots.title ? this.$slots.title() : this.title; const Title = title && ( -
+
{title}
); return ( - - - + {Title} + {this.genContent(title)} + {this.genButtons()} + ); }, }); diff --git a/src/dialog/README.md b/src/dialog/README.md index 4dbcace02..436f120de 100644 --- a/src/dialog/README.md +++ b/src/dialog/README.md @@ -84,7 +84,7 @@ export default { If you need to render vue components within a dialog, you can use dialog component. ```html - + ``` @@ -142,7 +142,7 @@ export default { | Attribute | Description | Type | Default | | --- | --- | --- | --- | -| v-model | Whether to show dialog | _boolean_ | - | +| v-model:show | Whether to show dialog | _boolean_ | - | | title | Title | _string_ | - | | width `v2.2.7` | Width | _number \| string_ | `320px` | | message | Message | _string_ | - | diff --git a/src/dialog/README.zh-CN.md b/src/dialog/README.zh-CN.md index 7ead0b38c..e69de29bb 100644 --- a/src/dialog/README.zh-CN.md +++ b/src/dialog/README.zh-CN.md @@ -1,220 +0,0 @@ -# Dialog 弹出框 - -### 介绍 - -弹出模态框,常用于消息提示、消息确认,或在当前页面内完成特定的交互操作。 - -弹出框组件支持函数调用和组件调用两种方式。 - -### 函数调用 - -Dialog 是一个函数,调用后会直接在页面中弹出相应的模态框。 - -```js -import { Dialog } from 'vant'; - -Dialog({ message: '提示' }); -``` - -### 组件调用 - -通过组件调用 Dialog 时,可以通过下面的方式进行注册: - -```js -import Vue from 'vue'; -import { Dialog } from 'vant'; - -// 全局注册 -Vue.use(Dialog); - -// 局部注册 -export default { - components: { - [Dialog.Component.name]: Dialog.Component, - }, -}; -``` - -## 代码演示 - -### 消息提示 - -用于提示一些消息,只包含一个确认按钮。 - -```js -Dialog.alert({ - title: '标题', - message: '弹窗内容', -}).then(() => { - // on close -}); - -Dialog.alert({ - message: '弹窗内容', -}).then(() => { - // on close -}); -``` - -### 消息确认 - -用于确认消息,包含取消和确认按钮。 - -```js -Dialog.confirm({ - title: '标题', - message: '弹窗内容', -}) - .then(() => { - // on confirm - }) - .catch(() => { - // on cancel - }); -``` - -### 异步关闭 - -通过 `beforeClose` 属性可以传入一个回调函数,在弹窗关闭前进行特定操作。 - -```js -function beforeClose(action, done) { - if (action === 'confirm') { - setTimeout(done, 1000); - } else { - done(); - } -} - -Dialog.confirm({ - title: '标题', - message: '弹窗内容', - beforeClose, -}); -``` - -### 全局方法 - -引入 Dialog 组件后,会自动在 Vue 的 prototype 上挂载 `$dialog` 方法,在所有组件内部都可以直接调用此方法。 - -```js -export default { - mounted() { - this.$dialog.alert({ - message: '弹窗内容', - }); - }, -}; -``` - -### 组件调用 - -如果需要在弹窗内嵌入组件或其他自定义内容,可以使用组件调用的方式。 - -```html - - - -``` - -```js -export default { - data() { - return { - show: false, - }; - }, -}; -``` - -## API - -### 方法 - -| 方法名 | 说明 | 参数 | 返回值 | -| --- | --- | --- | --- | -| Dialog | 展示弹窗 | `options` | `Promise` | -| Dialog.alert | 展示消息提示弹窗 | `options` | `Promise` | -| Dialog.confirm | 展示消息确认弹窗 | `options` | `Promise` | -| Dialog.setDefaultOptions | 修改默认配置,对所有 Dialog 生效 | `options` | `void` | -| Dialog.resetDefaultOptions | 重置默认配置,对所有 Dialog 生效 | - | `void` | -| Dialog.close | 关闭弹窗 | - | `void` | - -### Options - -通过函数调用 `Dialog` 时,支持传入以下选项: - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| title | 标题 | _string_ | - | -| width `v2.2.7` | 弹窗宽度,默认单位为`px` | _number \| string_ | `320px` | -| message | 文本内容,支持通过`\n`换行 | _string_ | - | -| messageAlign | 内容对齐方式,可选值为`left` `right` | _string_ | `center` | -| className | 自定义类名 | _any_ | - | -| showConfirmButton | 是否展示确认按钮 | _boolean_ | `true` | -| showCancelButton | 是否展示取消按钮 | _boolean_ | `false` | -| confirmButtonText | 确认按钮文案 | _string_ | `确认` | -| confirmButtonColor | 确认按钮颜色 | _string_ | `#1989fa` | -| cancelButtonText | 取消按钮文案 | _string_ | `取消` | -| cancelButtonColor | 取消按钮颜色 | _string_ | `black` | -| overlay | 是否展示遮罩层 | _boolean_ | `true` | -| overlayClass `v2.2.7` | 自定义遮罩层类名 | _string_ | - | -| overlayStyle `v2.2.7` | 自定义遮罩层样式 | _object_ | - | -| closeOnPopstate `v2.0.5` | 是否在页面回退时自动关闭 | _boolean_ | `true` | -| closeOnClickOverlay | 是否在点击遮罩层后关闭弹窗 | _boolean_ | `false` | -| lockScroll | 是否锁定背景滚动 | _boolean_ | `true` | -| allowHtml `v2.8.7` | 是否允许 message 内容中渲染 HTML | _boolean_ | `true` | -| beforeClose | 关闭前的回调函数,
调用 done() 后关闭弹窗,
调用 done(false) 阻止弹窗关闭 | _(action, done) => void_ | - | -| transition `v2.2.6` | 动画类名,等价于 [transtion](https://cn.vuejs.org/v2/api/index.html#transition) 的`name`属性 | _string_ | - | -| getContainer | 指定挂载的节点,[用法示例](#/zh-CN/popup#zhi-ding-gua-zai-wei-zhi) | _string \| () => Element_ | `body` | - -### Props - -通过组件调用 `Dialog` 时,支持以下 Props: - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| v-model | 是否显示弹窗 | _boolean_ | - | -| title | 标题 | _string_ | - | -| width `v2.2.7` | 弹窗宽度,默认单位为`px` | _number \| string_ | `320px` | -| message | 文本内容,支持通过`\n`换行 | _string_ | - | -| message-align | 内容对齐方式,可选值为`left` `right` | _string_ | `center` | -| show-confirm-button | 是否展示确认按钮 | _boolean_ | `true` | -| show-cancel-button | 是否展示取消按钮 | _boolean_ | `false` | -| confirm-button-text | 确认按钮文案 | _string_ | `确认` | -| confirm-button-color | 确认按钮颜色 | _string_ | `#1989fa` | -| cancel-button-text | 取消按钮文案 | _string_ | `取消` | -| cancel-button-color | 取消按钮颜色 | _string_ | `black` | -| overlay | 是否展示遮罩层 | _boolean_ | `true` | -| overlay-class `v2.2.7` | 自定义遮罩层类名 | _string_ | - | -| overlay-style `v2.2.7` | 自定义遮罩层样式 | _object_ | - | -| close-on-popstate `v2.0.5` | 是否在页面回退时自动关闭 | _boolean_ | `true` | -| close-on-click-overlay | 是否在点击遮罩层后关闭弹窗 | _boolean_ | `false` | -| 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_ | - | -| transition `v2.2.6` | 动画类名,等价于 [transtion](https://cn.vuejs.org/v2/api/index.html#transition) 的`name`属性 | _string_ | - | -| get-container | 指定挂载的节点,[用法示例](#/zh-CN/popup#zhi-ding-gua-zai-wei-zhi) | _string \| () => Element_ | - | - -### Events - -通过组件调用 `Dialog` 时,支持以下事件: - -| 事件 | 说明 | 回调参数 | -| ------- | ------------------------ | -------- | -| confirm | 点击确认按钮时触发 | - | -| cancel | 点击取消按钮时触发 | - | -| open | 打开弹窗时触发 | - | -| close | 关闭弹窗时触发 | - | -| opened | 打开弹窗且动画结束后触发 | - | -| closed | 关闭弹窗且动画结束后触发 | - | - -### Slots - -通过组件调用 `Dialog` 时,支持以下插槽: - -| 名称 | 说明 | -| ------- | ---------- | -| default | 自定义内容 | -| title | 自定义标题 | diff --git a/src/dialog/demo/index.vue b/src/dialog/demo/index.vue index 5b1fa2165..106491702 100644 --- a/src/dialog/demo/index.vue +++ b/src/dialog/demo/index.vue @@ -26,7 +26,7 @@ {{ t('componentCall') }} { - instance.value = value; - }); + methods: { + onToggle(show) { + this.dialogProps.show = show; + }, + }, + render() { + return ( + + ); + }, + }).mount(root); } function Dialog(options) { @@ -33,23 +42,31 @@ function Dialog(options) { } return new Promise((resolve, reject) => { - if (!instance || !isInDocument(instance.$el)) { + if (!instance) { initInstance(); } - Object.assign(instance, Dialog.currentOptions, options, { - resolve, - reject, - }); + instance.dialogProps = { + ...Dialog.currentOptions, + ...options, + callback: (action) => { + (action === 'confirm' ? resolve : reject)(action); + }, + }; + + nextTick(() => { + instance.dialogProps.show = true; + }) }); } Dialog.defaultOptions = { - value: true, + show: false, title: '', width: '', message: '', overlay: true, + callback: null, className: '', allowHtml: true, lockScroll: true, @@ -67,9 +84,6 @@ Dialog.defaultOptions = { showCancelButton: false, closeOnPopstate: true, closeOnClickOverlay: false, - callback: (action) => { - instance[action === 'confirm' ? 'resolve' : 'reject'](action); - }, }; Dialog.alert = Dialog; @@ -96,12 +110,12 @@ Dialog.resetDefaultOptions = () => { Dialog.resetDefaultOptions(); -Dialog.install = () => { - Vue.use(VanDialog); +Dialog.install = (app) => { + console.log('use VanDialog', VanDialog); + app.use(VanDialog); + app.config.globalProperties.$dialog = Dialog; }; Dialog.Component = VanDialog; -Vue.prototype.$dialog = Dialog; - export default Dialog; diff --git a/src/dialog/index.less b/src/dialog/index.less index 0448d3f55..d95cd7477 100644 --- a/src/dialog/index.less +++ b/src/dialog/index.less @@ -1,7 +1,6 @@ @import '../style/var'; .van-dialog { - position: fixed; top: 45%; left: 50%; width: @dialog-width; @@ -9,7 +8,6 @@ font-size: @dialog-font-size; background-color: @dialog-background-color; border-radius: @dialog-border-radius; - transform: translate3d(-50%, -50%, 0); backface-visibility: hidden; // avoid blurry text after scale animation transition: @dialog-transition; transition-property: transform, opacity; @@ -80,7 +78,7 @@ } } - &-bounce-enter { + &-bounce-enter-from { transform: translate3d(-50%, -50%, 0) scale(0.7); opacity: 0; } diff --git a/vant.config.js b/vant.config.js index 5553be02e..56b13d3e8 100644 --- a/vant.config.js +++ b/vant.config.js @@ -184,10 +184,10 @@ module.exports = { path: 'action-sheet', title: 'ActionSheet 动作面板', }, - // { - // path: 'dialog', - // title: 'Dialog 弹出框', - // }, + { + path: 'dialog', + title: 'Dialog 弹出框', + }, // { // path: 'dropdown-menu', // title: 'DropdownMenu 下拉菜单', @@ -518,10 +518,10 @@ module.exports = { path: 'action-sheet', title: 'ActionSheet', }, - // { - // path: 'dialog', - // title: 'Dialog', - // }, + { + path: 'dialog', + title: 'Dialog', + }, // { // path: 'dropdown-menu', // title: 'DropdownMenu',