[Improvement] Dialog: add before-close prop (#881)

This commit is contained in:
neverland 2018-04-17 14:16:28 +08:00 committed by GitHub
parent f87dd825d7
commit 6d74198e27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 51 deletions

View File

@ -13,7 +13,8 @@
<van-button @click="show = true">{{ $t('advancedUsage') }}</van-button> <van-button @click="show = true">{{ $t('advancedUsage') }}</van-button>
<van-dialog <van-dialog
v-model="show" v-model="show"
:asyncConfirm="onClickConfirmAsync" show-cancel-button
:before-close="beforeClose"
> >
<van-field <van-field
v-model="username" v-model="username"
@ -59,7 +60,7 @@ export default {
Dialog.alert({ Dialog.alert({
title: this.$t('title'), title: this.$t('title'),
message: this.$t('content') message: this.$t('content')
}) });
}, },
onClickAlert2() { onClickAlert2() {
@ -75,12 +76,12 @@ export default {
}); });
}, },
onClickConfirmAsync() { beforeClose(action, done) {
return new Promise((resolve, reject) => { if (action === 'confirm') {
setTimeout(() => { setTimeout(done, 1000);
resolve() } else {
}, 1000) done();
}) }
} }
} }
}; };

View File

@ -77,6 +77,7 @@ export default {
| overlay | Whether to show overlay | `Boolean` | `true` | - | | overlay | Whether to show overlay | `Boolean` | `true` | - |
| closeOnClickOverlay | Whether to close when click overlay | `Boolean` | `false` | - | | closeOnClickOverlay | Whether to close when click overlay | `Boolean` | `false` | - |
| lockScroll | Whether to lock body scroll | `Boolean` | `true` | - | | lockScroll | Whether to lock body scroll | `Boolean` | `true` | - |
| beforeClose | Callback before closecall done to close dialog | (action: string, done: function) => void | - | - |
#### Advanced Usage #### Advanced Usage
If you need to render vue components within a dialog, you can use dialog component. If you need to render vue components within a dialog, you can use dialog component.
@ -110,12 +111,12 @@ export default {
}, },
methods: { methods: {
onClickConfirmAsync() { beforeClose() {
return new Promise((resolve, reject) => { if (action === 'confirm') {
setTimeout(() => { setTimeout(done, 1000);
resolve() } else {
}, 1000) done();
}) }
} }
} }
} }
@ -136,6 +137,7 @@ export default {
| overlay | Whether to show overlay | `Boolean` | `true` | - | | overlay | Whether to show overlay | `Boolean` | `true` | - |
| close-on-click-overlay | Whether to close when click overlay | `Boolean` | `false` | - | | close-on-click-overlay | Whether to close when click overlay | `Boolean` | `false` | - |
| lock-scroll | Whether to lock background scroll | `Boolean` | `true` | - | | lock-scroll | Whether to lock background scroll | `Boolean` | `true` | - |
| before-close | Callback before closecall done to close dialog | (action: string, done: function) => void | - | - |
### Event ### Event

View File

@ -78,13 +78,18 @@ export default {
| overlay | 是否展示蒙层 | `Boolean` | `true` | - | | overlay | 是否展示蒙层 | `Boolean` | `true` | - |
| closeOnClickOverlay | 点击蒙层时是否关闭弹窗 | `Boolean` | `false` | - | | closeOnClickOverlay | 点击蒙层时是否关闭弹窗 | `Boolean` | `false` | - |
| lockScroll | 是否锁定背景滚动 | `Boolean` | `true` | - | | lockScroll | 是否锁定背景滚动 | `Boolean` | `true` | - |
| beforeClose | 关闭前的回调函数,调用 done 后关闭弹窗 | (action: string, done: function) => void | - | - |
#### 高级用法 #### 高级用法
如果需要在弹窗内实现更复杂的交互,可以通过组件形式来调用 Dialog 如果需要在弹窗内实现更复杂的交互,可以通过组件形式来调用 Dialog
```html ```html
<van-dialog v-model="show" :asyncConfirm="onClickConfirmAsync"> <van-dialog
v-model="show"
show-cancel-button
:before-close="beforeClose"
>
<van-field <van-field
v-model="username" v-model="username"
label="用户名" label="用户名"
@ -112,12 +117,12 @@ export default {
}, },
methods: { methods: {
onClickConfirmAsync() { beforeClose() {
return new Promise((resolve, reject) => { if (action === 'confirm') {
setTimeout(() => { setTimeout(done, 1000);
resolve(); } else {
}, 1000) done();
}); }
} }
} }
} }
@ -130,7 +135,6 @@ export default {
| v-model | 是否显示弹窗 | `Boolean` | - | - | | v-model | 是否显示弹窗 | `Boolean` | - | - |
| title | 标题 | `String` | - | - | | title | 标题 | `String` | - | - |
| message | 内容 | `String` | - | - | | message | 内容 | `String` | - | - |
| async-confirm | dialog是否异步关闭传入一个返回Promise的函数在点击确定时触发。 | `Function` | - | - |
| show-confirm-button | 是否展示确认按钮 | `Boolean` | `true` | - | | show-confirm-button | 是否展示确认按钮 | `Boolean` | `true` | - |
| show-cancel-button | 是否展示取消按钮 | `Boolean` | `false` | - | | show-cancel-button | 是否展示取消按钮 | `Boolean` | `false` | - |
| confirm-button-text | 确认按钮的文案 | `String` | `确认` | - | | confirm-button-text | 确认按钮的文案 | `String` | `确认` | - |
@ -138,6 +142,7 @@ export default {
| overlay | 是否展示蒙层 | `Boolean` | `true` | - | | overlay | 是否展示蒙层 | `Boolean` | `true` | - |
| close-on-click-overlay | 点击蒙层时是否关闭弹窗 | `Boolean` | `false` | - | | close-on-click-overlay | 点击蒙层时是否关闭弹窗 | `Boolean` | `false` | - |
| lock-scroll | 是否锁定背景滚动 | `Boolean` | `true` | - | | lock-scroll | 是否锁定背景滚动 | `Boolean` | `true` | - |
| before-close | 关闭前的回调函数,调用 done 后关闭弹窗 | (action: string, done: function) => void | - | - |
### Event ### Event

View File

@ -9,19 +9,20 @@
</div> </div>
<div class="van-dialog__footer" :class="{ 'is-twobtn': showCancelButton && showConfirmButton }"> <div class="van-dialog__footer" :class="{ 'is-twobtn': showCancelButton && showConfirmButton }">
<van-button <van-button
v-show="showCancelButton"
:loading="loading.cancel"
size="large" size="large"
class="van-dialog__cancel" class="van-dialog__cancel"
v-show="showCancelButton"
@click="handleAction('cancel')" @click="handleAction('cancel')"
> >
{{ cancelButtonText || $t('cancel') }} {{ cancelButtonText || $t('cancel') }}
</van-button> </van-button>
<van-button <van-button
size="large"
class="van-dialog__confirm"
:loading="confirmButtonLoading"
:class="{ 'van-hairline--left': showCancelButton && showConfirmButton }"
v-show="showConfirmButton" v-show="showConfirmButton"
size="large"
:loading="loading.confirm"
class="van-dialog__confirm"
:class="{ 'van-hairline--left': showCancelButton && showConfirmButton }"
@click="handleAction('confirm')" @click="handleAction('confirm')"
> >
{{ confirmButtonText || $t('confirm') }} {{ confirmButtonText || $t('confirm') }}
@ -39,18 +40,6 @@ import Popup from '../mixins/popup';
export default create({ export default create({
name: 'dialog', name: 'dialog',
data() {
return {
confirmButtonLoading: false
};
},
watch: {
value(val) {
this.confirmButtonLoading = !val && false;
}
},
components: { components: {
VanButton VanButton
}, },
@ -61,7 +50,7 @@ export default create({
title: String, title: String,
message: String, message: String,
callback: Function, callback: Function,
asyncConfirm: Function, beforeClose: Function,
confirmButtonText: String, confirmButtonText: String,
cancelButtonText: String, cancelButtonText: String,
showCancelButton: Boolean, showCancelButton: Boolean,
@ -79,19 +68,31 @@ export default create({
} }
}, },
data() {
return {
loading: {
confirm: false,
cancel: false
}
};
},
methods: { methods: {
handleAction(action) { handleAction(action) {
if ((action === 'confirm') && this.asyncConfirm) { if (this.beforeClose) {
this.confirmButtonLoading = true; this.loading[action] = true;
this.asyncConfirm(action).then(res => { this.beforeClose(action, () => {
this.$emit('input', false); this.onClose(action);
}).catch(err => { this.loading[action] = false;
this.confirmButtonLoading = false;
}); });
} else { } else {
this.$emit('input', false); this.onClose(action);
this.$emit(action);
} }
},
onClose(action) {
this.$emit('input', false);
this.$emit(action);
this.callback && this.callback(action); this.callback && this.callback(action);
} }
} }

View File

@ -35,6 +35,7 @@ Dialog.defaultOptions = {
message: '', message: '',
overlay: true, overlay: true,
lockScroll: true, lockScroll: true,
beforeClose: null,
confirmButtonText: '', confirmButtonText: '',
cancelButtonText: '', cancelButtonText: '',
showConfirmButton: true, showConfirmButton: true,

View File

@ -7,6 +7,7 @@ describe('Dialog', () => {
}); });
it('create a alert dialog', (done) => { it('create a alert dialog', (done) => {
Dialog.close();
Dialog.alert({ Dialog.alert({
title: 'title', title: 'title',
message: 'message' message: 'message'
@ -19,7 +20,7 @@ describe('Dialog', () => {
expect(document.querySelector('.van-dialog')).to.exist; expect(document.querySelector('.van-dialog')).to.exist;
expect(document.querySelector('.van-dialog__cancel').style.display).to.equal('none'); expect(document.querySelector('.van-dialog__cancel').style.display).to.equal('none');
document.querySelector('.van-dialog__confirm').click(); document.querySelector('.van-dialog__confirm').click();
}, 500); }, 300);
}); });
it('create a confirm dialog', (done) => { it('create a confirm dialog', (done) => {
@ -35,7 +36,7 @@ describe('Dialog', () => {
setTimeout(() => { setTimeout(() => {
document.querySelector('.van-dialog__cancel').click(); document.querySelector('.van-dialog__cancel').click();
}, 500); }, 300);
}); });
it('create a confirm dialog with callback', (done) => { it('create a confirm dialog with callback', (done) => {
@ -48,7 +49,7 @@ describe('Dialog', () => {
setTimeout(() => { setTimeout(() => {
document.querySelector('.van-dialog__cancel').click(); document.querySelector('.van-dialog__cancel').click();
}, 500); }, 300);
}); });
it('set default options', () => { it('set default options', () => {
@ -64,4 +65,23 @@ describe('Dialog', () => {
Vue.use(Dialog); Vue.use(Dialog);
expect(!!Vue.component('van-dialog')).to.be.true; expect(!!Vue.component('van-dialog')).to.be.true;
}); });
it('before close', (done) => {
Dialog.confirm({
beforeClose(action, dialogDone) {
setTimeout(() => {
dialogDone();
setTimeout(() => {
expect(document.querySelector('.van-dialog').style.display).to.equal('none');
done();
}, 300);
});
}
});
setTimeout(() => {
document.querySelector('.van-dialog__confirm').click();
expect(document.querySelector('.van-dialog').style.display).to.equal('');
}, 300);
});
}); });

1
types/dialog.d.ts vendored
View File

@ -3,6 +3,7 @@ export type DialogOptions = {
message?: string; message?: string;
overlay?: boolean; overlay?: boolean;
lockScroll?: boolean; lockScroll?: boolean;
beforeClose?: (action: string, done: function) => void;
confirmButtonText?: string; confirmButtonText?: string;
cancelButtonText?: string; cancelButtonText?: string;
showConfirmButton?: boolean; showConfirmButton?: boolean;