Dialog: support both function call and component call

This commit is contained in:
陈嘉涵 2017-08-25 15:37:39 +08:00
parent 34696d3f6e
commit 43693fa781
6 changed files with 131 additions and 152 deletions

View File

@ -9,33 +9,29 @@
<script> <script>
import { Dialog } from 'packages/index'; import { Dialog } from 'packages/index';
const message = '弹窗内容';
export default { export default {
methods: { methods: {
handleAlertClick() { onClickAlert() {
Dialog.alert({ Dialog.alert({
title: 'alert标题', title: '标题',
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。' message
}).then((action) => {
console.log(action);
}); });
}, },
handleAlert2Click() { onClickAlert2() {
Dialog.alert({ Dialog.alert({
message: '无标题alert' message
}).then((action) => {
console.log(action);
}); });
}, },
handleConfirmClick() { onClickConfirm() {
Dialog.confirm({ Dialog.confirm({
title: 'confirm标题', title: '标题',
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。' message
}).then((action) => { }).catch(action => {
console.log(action); console.log(action);
}, (error) => {
console.log(error);
}); });
} }
} }
@ -46,8 +42,6 @@ export default {
### 使用指南 ### 使用指南
`Dialog`和其他组件不同不是通过HTML结构的方式来使用而是通过函数调用的方式。使用前需要先引入它它接受一个数组作为参数数组中的每一项对应了图片链接。
```js ```js
import { Dialog } from 'vant'; import { Dialog } from 'vant';
``` ```
@ -56,30 +50,30 @@ import { Dialog } from 'vant';
#### 消息提示 #### 消息提示
用于提示一些消息,只包含一个确认按钮 用于提示一些消息,只包含一个确认按钮
:::demo 消息提示 :::demo 消息提示
```html ```html
<van-button @click="handleAlertClick">alert</van-button> <van-button @click="onClickAlert">Alert</van-button>
<van-button @click="handleAlert2Click">无标题alert</van-button> <van-button @click="onClickAlert2">无标题 Alert</van-button>
<script> <script>
export default { export default {
methods: { methods: {
handleAlertClick() { onClickAlert() {
Dialog.alert({ Dialog.alert({
title: 'alert标题', title: '标题',
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。' message: '弹窗内容'
}).then((action) => { }).then(() => {
console.log(action); // on close
}); });
}, },
handleAlert2Click() { onClickAlert2() {
Dialog.alert({ Dialog.alert({
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。' message: '弹窗内容'
}).then((action) => { }).then(() => {
console.log(action); // on close
}); });
} }
} }
@ -90,23 +84,23 @@ export default {
#### 消息确认 #### 消息确认
用于确认消息,包含取消和确认按钮 用于确认消息,包含取消和确认按钮
:::demo 消息确认 :::demo 消息确认
```html ```html
<van-button @click="handleConfirmClick">confirm</van-button> <van-button @click="onClickConfirm">Confirm</van-button>
<script> <script>
export default { export default {
methods: { methods: {
handleConfirmClick() { onClickConfirm() {
Dialog.confirm({ Dialog.confirm({
title: 'confirm标题', title: '标题',
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。' message: '弹窗内容'
}).then((action) => { }).then(() => {
console.log(action); // on confirm
}, (error) => { }).catch(() => {
console.log(error); // on cancel
}); });
} }
} }
@ -117,19 +111,22 @@ export default {
### 方法 ### 方法
#### Dialog.alert(options) | 方法名 | 参数 | 返回值 | 介绍 |
|-----------|-----------|-----------|-------------|
消息提示时使用该方法。 | Dialog.alert | options | `Promise` | 展示消息提示弹窗 |
| Dialog.confirm | options | `Promise` | 展示消息确认弹窗 |
#### Dialog.confirm(options) | Dialog.close | - | `void` | 关闭弹窗 |
消息确认时使用该方法。
### Options ### Options
| 参数 | 说明 | 类型 | 默认值 | 可选值 | | 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------| |-----------|-----------|-----------|-------------|-------------|
| title | 标题 | `string` | | | | title | 标题 | `String` | | |
| message | 内容 | `string` | | | | message | 内容 | `String` | | |
| confirmButtonText | 确认按钮的文案 | `string` | `确认` | | | showConfirmButton | 是否展示确认按钮 | `Boolean` | `true` | |
| cancelButtonText | 取消按钮的文案 | `string` | `取消` | | | showCancelButton | 是否展示取消按钮 | `Boolean` | `false` | |
| confirmButtonText | 确认按钮的文案 | `String` | `确认` | |
| cancelButtonText | 取消按钮的文案 | `String` | `取消` | |
| overlay | 是否展示蒙层 | `Boolean` | `true` | |
| closeOnClickOverlay | 点击蒙层时是否关闭弹窗 | `Boolean` | `false` | |
| lockOnScroll | 是否禁用背景滚动 | `Boolean` | `true` | |

View File

@ -2,8 +2,10 @@
<transition name="van-dialog-bounce"> <transition name="van-dialog-bounce">
<div class="van-dialog" v-show="value"> <div class="van-dialog" v-show="value">
<div class="van-dialog__header" v-if="title" v-text="title" /> <div class="van-dialog__header" v-if="title" v-text="title" />
<div class="van-dialog__content" v-if="message"> <div class="van-dialog__content">
<div class="van-dialog__message" :class="{ 'van-dialog__message--withtitle': title }" v-html="message" /> <slot>
<div class="van-dialog__message" v-if="message" :class="{ 'van-dialog__message--withtitle': title }" v-html="message" />
</slot>
</div> </div>
<div class="van-dialog__footer" :class="{ 'is-twobtn': showCancelButton && showConfirmButton }"> <div class="van-dialog__footer" :class="{ 'is-twobtn': showCancelButton && showConfirmButton }">
<van-button size="large" class="van-dialog__cancel" v-show="showCancelButton" @click="handleAction('cancel')">{{ cancelButtonText }}</van-button> <van-button size="large" class="van-dialog__cancel" v-show="showCancelButton" @click="handleAction('cancel')">{{ cancelButtonText }}</van-button>
@ -27,33 +29,48 @@ export default {
mixins: [Popup], mixins: [Popup],
props: { props: {
title: {
type: String,
default: ''
},
message: {
type: String,
default: ''
},
showConfirmButton: {
type: Boolean,
default: true
},
showCancelButton: {
type: Boolean,
default: false
},
confirmButtonText: {
type: String,
default: '确认'
},
cancelButtonText: {
type: String,
default: '取消'
},
callback: {
type: Function
},
overlay: { overlay: {
default: true default: true
}, },
closeOnClickOverlay: { closeOnClickOverlay: {
default: true default: false
}, },
lockOnScroll: { lockOnScroll: {
default: true default: true
} }
}, },
data() {
return {
title: '',
message: '',
type: '',
showConfirmButton: true,
showCancelButton: false,
confirmButtonText: '确认',
cancelButtonText: '取消',
callback: null
};
},
methods: { methods: {
handleAction(action) { handleAction(action) {
this.$emit('input', false); this.$emit('input', false);
this.$emit(action);
this.callback && this.callback(action); this.callback && this.callback(action);
} }
} }

View File

@ -1,97 +1,62 @@
import Vue from 'vue'; import Vue from 'vue';
import Dialog from './dialog'; import DialogComponent from './dialog';
const DialogConstructor = Vue.extend(Dialog);
let currentDialog;
let instance; let instance;
let dialogQueue = [];
const defaultCallback = action => { const defaultConfig = {
/* istanbul ignore else */ value: true,
if (currentDialog) { title: '',
if (currentDialog.resolve && action === 'confirm') { message: '',
currentDialog.resolve(action); showCancelButton: false,
} else if (currentDialog.reject && action === 'cancel') { closeOnClickOverlay: false,
currentDialog.reject(action); callback: action => {
} instance[action === 'confirm' ? 'resolve' : 'reject'](action);
} }
}; };
const initInstance = () => { const initInstance = () => {
const DialogConstructor = Vue.extend(DialogComponent);
instance = new DialogConstructor({ instance = new DialogConstructor({
el: document.createElement('div') el: document.createElement('div')
}); });
instance.$on('input', value => { instance.$on('input', value => {
instance.value = value; instance.value = value;
}) });
instance.callback = defaultCallback;
document.body.appendChild(instance.$el);
}; };
const showNextDialog = () => { const Dialog = options => {
if (!instance) { return new Promise((resolve, reject) => {
initInstance(); if (!instance) {
} initInstance();
/* istanbul ignore else */
if (!instance.value && dialogQueue.length > 0) {
currentDialog = dialogQueue.shift();
const { options } = currentDialog;
for (const prop in options) {
/* istanbul ignore else */
if (options.hasOwnProperty(prop)) {
instance[prop] = options[prop];
}
} }
instance.callback = options.callback || defaultCallback; Object.assign(instance, {
instance.value = true; resolve,
document.body.appendChild(instance.$el); reject,
} ...options
};
const DialogBox = options => {
return new Promise((resolve, reject) => { // eslint-disable-line
dialogQueue.push({
options: { ...options },
callback: options.callback,
resolve: resolve,
reject: reject
}); });
showNextDialog();
}); });
}; };
DialogBox.alert = function(options) { Dialog.alert = options => Dialog({
return DialogBox({ ...defaultConfig,
type: 'alert', ...options
title: '', });
message: '',
closeOnClickOverlay: false,
showCancelButton: false,
...options
});
};
DialogBox.confirm = function(options) { Dialog.confirm = options => Dialog({
return DialogBox({ ...defaultConfig,
type: 'confirm', showCancelButton: true,
title: '', ...options
message: '', });
closeOnClickOverlay: true,
showCancelButton: true,
...options
});
};
DialogBox.close = function() { Dialog.close = () => {
instance.value = false; instance.value = false;
dialogQueue = [];
currentDialog = null;
}; };
export default DialogBox; export default Dialog;
export {
Dialog
};

View File

@ -11,7 +11,6 @@
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
outline: 0; outline: 0;
overflow: hidden;
-webkit-appearance: none; -webkit-appearance: none;
&::after { &::after {

View File

@ -42,9 +42,10 @@
overflow: hidden; overflow: hidden;
&.is-twobtn { &.is-twobtn {
display: flex;
.van-button { .van-button {
width: 50%; flex: 1;
float: left;
} }
.van-dialog__cancel { .van-dialog__cancel {
@ -63,7 +64,10 @@
} }
&__confirm { &__confirm {
color: #00C000; &,
&:active {
color: #00C000;
}
} }
&-bounce-enter { &-bounce-enter {

View File

@ -3,11 +3,6 @@ import Vue from 'vue';
describe('Dialog', () => { describe('Dialog', () => {
afterEach(() => { afterEach(() => {
const el = document.querySelector('.van-dialog');
if (!el) return;
if (el.parentNode) {
el.parentNode.removeChild(el);
}
Dialog.close(); Dialog.close();
}); });
@ -28,30 +23,32 @@ describe('Dialog', () => {
}, 500); }, 500);
}); });
it('create a confirm dialog', () => { it('create a confirm dialog', (done) => {
Dialog.confirm({ Dialog.confirm({
title: 'title', title: 'title',
message: 'message' message: 'message'
}).catch((action) => {
expect(action).to.equal('cancel');
done();
}); });
expect(document.querySelector('.van-dialog')).to.exist; expect(document.querySelector('.van-dialog')).to.exist;
setTimeout(() => {
document.querySelector('.van-dialog__cancel').click();
}, 500);
}); });
it('create a confirm dialog with callback', (done) => { it('create a confirm dialog with callback', (done) => {
let dialogAction;
Dialog.confirm({ Dialog.confirm({
title: 'title',
message: 'message',
callback: (action) => { callback: (action) => {
dialogAction = action; expect(action).to.equal('cancel');
done();
} }
}); });
expect(document.querySelector('.van-dialog')).to.exist;
setTimeout(() => { setTimeout(() => {
document.querySelector('.van-dialog__cancel').click(); document.querySelector('.van-dialog__cancel').click();
expect(dialogAction).to.equal('cancel');
done();
}, 500); }, 500);
}); });
}); });