refactor(Dialog): refactor with composition api

This commit is contained in:
chenjiahan 2020-09-04 16:53:22 +08:00
parent 902a1b7c63
commit 2b8284a227
2 changed files with 147 additions and 172 deletions

View File

@ -1,25 +1,32 @@
import { reactive } from 'vue';
// Utils // Utils
import { createNamespace, addUnit, pick } from '../utils'; import { createNamespace, addUnit, pick } from '../utils';
import { BORDER_TOP, BORDER_LEFT } from '../utils/constant'; import { BORDER_TOP, BORDER_LEFT } from '../utils/constant';
// Components // Components
import Popup from '../popup'; import Popup, { popupSharedProps } from '../popup';
import Button from '../button'; import Button from '../button';
import ActionBar from '../action-bar'; import ActionBar from '../action-bar';
import ActionBarButton from '../action-bar-button'; import ActionBarButton from '../action-bar-button';
const [createComponent, bem, t] = createNamespace('dialog'); const [createComponent, bem, t] = createNamespace('dialog');
const popupKeys = [
...Object.keys(popupSharedProps),
'transition',
'closeOnPopstate',
];
export default createComponent({ export default createComponent({
props: { props: {
show: Boolean, ...popupSharedProps,
title: String, title: String,
theme: String, theme: String,
width: [Number, String], width: [Number, String],
message: String, message: String,
className: null,
callback: Function, callback: Function,
lazyRender: Boolean, className: null,
beforeClose: Function, beforeClose: Function,
messageAlign: String, messageAlign: String,
showCancelButton: Boolean, showCancelButton: Boolean,
@ -28,10 +35,6 @@ export default createComponent({
confirmButtonText: String, confirmButtonText: String,
confirmButtonColor: String, confirmButtonColor: String,
closeOnClickOverlay: Boolean, closeOnClickOverlay: Boolean,
overlay: {
type: Boolean,
default: true,
},
allowHtml: { allowHtml: {
type: Boolean, type: Boolean,
default: true, default: true,
@ -52,180 +55,160 @@ export default createComponent({
emits: ['confirm', 'cancel', 'update:show'], emits: ['confirm', 'cancel', 'update:show'],
data() { setup(props, { emit, slots }) {
return { const loading = reactive({
loading: { confirm: false,
confirm: false, cancel: false,
cancel: false, });
},
const onUpdateShow = (value) => {
emit('update:show', value);
}; };
},
methods: { const close = (action) => {
onClickOverlay() { onUpdateShow(false);
this.handleAction('overlay'); if (props.callback) {
}, props.callback(action);
}
};
handleAction(action) { const handleAction = (action) => {
this.$emit(action); // should not trigger close event when hidden
if (!props.show) {
// show not trigger close event when hidden
if (!this.show) {
return; return;
} }
if (this.beforeClose) { emit(action);
this.loading[action] = true;
this.beforeClose(action, (state) => {
if (state !== false && this.loading[action]) {
this.onClose(action);
}
this.loading.confirm = false; if (props.beforeClose) {
this.loading.cancel = false; loading[action] = true;
props.beforeClose(action, (result) => {
if (result !== false && loading[action]) {
close(action);
}
loading[action] = false;
}); });
} else { } else {
this.onClose(action); close(action);
} }
}, };
onClose(action) {
this.onUpdateShow(false);
if (this.callback) {
this.callback(action);
}
},
onUpdateShow(value) {
this.$emit('update:show', value);
},
genRoundButtons() {
return (
<ActionBar class={bem('footer')}>
{this.showCancelButton && (
<ActionBarButton
size="large"
type="warning"
text={this.cancelButtonText || t('cancel')}
class={bem('cancel')}
color={this.cancelButtonColor}
loading={this.loading.cancel}
onClick={() => {
this.handleAction('cancel');
}}
/>
)}
{this.showConfirmButton && (
<ActionBarButton
size="large"
type="danger"
text={this.confirmButtonText || t('confirm')}
class={bem('confirm')}
color={this.confirmButtonColor}
loading={this.loading.confirm}
onClick={() => {
this.handleAction('confirm');
}}
/>
)}
</ActionBar>
);
},
genButtons() {
const multiple = this.showCancelButton && this.showConfirmButton;
return (
<div class={[BORDER_TOP, bem('footer')]}>
{this.showCancelButton && (
<Button
size="large"
class={bem('cancel')}
loading={this.loading.cancel}
text={this.cancelButtonText || t('cancel')}
style={{ color: this.cancelButtonColor }}
onClick={() => {
this.handleAction('cancel');
}}
/>
)}
{this.showConfirmButton && (
<Button
size="large"
class={[bem('confirm'), { [BORDER_LEFT]: multiple }]}
loading={this.loading.confirm}
text={this.confirmButtonText || t('confirm')}
style={{ color: this.confirmButtonColor }}
onClick={() => {
this.handleAction('confirm');
}}
/>
)}
</div>
);
},
genContent(hasTitle) {
if (this.$slots.default) {
return <div class={bem('content')}>{this.$slots.default()}</div>;
}
const { message, messageAlign } = this;
if (message) {
const data = {
class: bem('message', {
'has-title': hasTitle,
[messageAlign]: messageAlign,
}),
[this.allowHtml ? 'innerHTML' : 'textContent']: message,
};
const renderTitle = () => {
const title = slots.title ? slots.title() : props.title;
if (title) {
return ( return (
<div class={bem('content')}> <div
<div {...data} /> class={bem('header', {
isolated: !props.message && !slots.default,
})}
>
{title}
</div> </div>
); );
} }
}, };
},
render() { const renderContent = () => {
const { message } = this; if (slots.default) {
const title = this.$slots.title ? this.$slots.title() : this.title; return <div class={bem('content')}>{slots.default()}</div>;
const Title = title && ( }
<div
class={bem('header', { isolated: !message && !this.$slots.default })} const { title, message, allowHtml, messageAlign } = props;
> if (message) {
{title} return (
<div class={bem('content')}>
<div
class={bem('message', {
'has-title': slots.title || title,
[messageAlign]: messageAlign,
})}
{...{
[allowHtml ? 'innerHTML' : 'textContent']: message,
}}
/>
</div>
);
}
};
const renderButtons = () => (
<div class={[BORDER_TOP, bem('footer')]}>
{props.showCancelButton && (
<Button
size="large"
text={props.cancelButtonText || t('cancel')}
class={bem('cancel')}
style={{ color: props.cancelButtonColor }}
loading={loading.cancel}
onClick={() => {
handleAction('cancel');
}}
/>
)}
{props.showConfirmButton && (
<Button
size="large"
text={props.confirmButtonText || t('confirm')}
class={[bem('confirm'), { [BORDER_LEFT]: props.showCancelButton }]}
style={{ color: props.confirmButtonColor }}
loading={loading.confirm}
onClick={() => {
handleAction('confirm');
}}
/>
)}
</div> </div>
); );
return ( const renderRoundButtons = () => (
<Popup <ActionBar class={bem('footer')}>
role="dialog" {props.showCancelButton && (
class={[bem([this.theme]), this.className]} <ActionBarButton
style={{ width: addUnit(this.width) }} size="large"
aria-labelledby={this.title || message} type="warning"
{...{ text={props.cancelButtonText || t('cancel')}
...pick(this, [ class={bem('cancel')}
'show', color={props.cancelButtonColor}
'overlay', loading={loading.cancel}
'transition', onClick={() => {
'lazyRender', handleAction('cancel');
'closeOnPopstate', }}
'closeOnClickOverlay', />
]), )}
'onUpdate:show': this.onUpdateShow, {props.showConfirmButton && (
}} <ActionBarButton
> size="large"
{Title} type="danger"
{this.genContent(title)} text={props.confirmButtonText || t('confirm')}
{this.theme === 'round-button' class={bem('confirm')}
? this.genRoundButtons() color={props.confirmButtonColor}
: this.genButtons()} loading={loading.confirm}
</Popup> onClick={() => {
handleAction('confirm');
}}
/>
)}
</ActionBar>
); );
return () => {
const { width, title, theme, message, className } = props;
return (
<Popup
role="dialog"
class={[bem([theme]), className]}
style={{ width: addUnit(width) }}
aria-labelledby={title || message}
{...{
...pick(props, popupKeys),
'onUpdate:show': onUpdateShow,
}}
>
{renderTitle()}
{renderContent()}
{theme === 'round-button' ? renderRoundButtons() : renderButtons()}
</Popup>
);
};
}, },
}); });

View File

@ -8,15 +8,7 @@ function initInstance() {
const Wrapper = { const Wrapper = {
setup() { setup() {
const { state, toggle } = usePopupState(); const { state, toggle } = usePopupState();
return () => ( return () => <VanDialog {...{ ...state, 'onUpdate:show': toggle }} />;
<VanDialog
lazyRender={false}
{...{
...state,
'onUpdate:show': toggle,
}}
/>
);
}, },
}; };