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) { const renderTitle = () => {
this.onUpdateShow(false); const title = slots.title ? slots.title() : props.title;
if (title) {
if (this.callback) {
this.callback(action);
}
},
onUpdateShow(value) {
this.$emit('update:show', value);
},
genRoundButtons() {
return ( return (
<ActionBar class={bem('footer')}> <div
{this.showCancelButton && ( class={bem('header', {
<ActionBarButton isolated: !props.message && !slots.default,
})}
>
{title}
</div>
);
}
};
const renderContent = () => {
if (slots.default) {
return <div class={bem('content')}>{slots.default()}</div>;
}
const { title, message, allowHtml, messageAlign } = props;
if (message) {
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" size="large"
type="warning" text={props.cancelButtonText || t('cancel')}
text={this.cancelButtonText || t('cancel')}
class={bem('cancel')} class={bem('cancel')}
color={this.cancelButtonColor} style={{ color: props.cancelButtonColor }}
loading={this.loading.cancel} loading={loading.cancel}
onClick={() => { onClick={() => {
this.handleAction('cancel'); handleAction('cancel');
}} }}
/> />
)} )}
{this.showConfirmButton && ( {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>
);
const renderRoundButtons = () => (
<ActionBar class={bem('footer')}>
{props.showCancelButton && (
<ActionBarButton
size="large"
type="warning"
text={props.cancelButtonText || t('cancel')}
class={bem('cancel')}
color={props.cancelButtonColor}
loading={loading.cancel}
onClick={() => {
handleAction('cancel');
}}
/>
)}
{props.showConfirmButton && (
<ActionBarButton <ActionBarButton
size="large" size="large"
type="danger" type="danger"
text={this.confirmButtonText || t('confirm')} text={props.confirmButtonText || t('confirm')}
class={bem('confirm')} class={bem('confirm')}
color={this.confirmButtonColor} color={props.confirmButtonColor}
loading={this.loading.confirm} loading={loading.confirm}
onClick={() => { onClick={() => {
this.handleAction('confirm'); handleAction('confirm');
}} }}
/> />
)} )}
</ActionBar> </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,
};
return (
<div class={bem('content')}>
<div {...data} />
</div>
);
}
},
},
render() {
const { message } = this;
const title = this.$slots.title ? this.$slots.title() : this.title;
const Title = title && (
<div
class={bem('header', { isolated: !message && !this.$slots.default })}
>
{title}
</div>
);
return () => {
const { width, title, theme, message, className } = props;
return ( return (
<Popup <Popup
role="dialog" role="dialog"
class={[bem([this.theme]), this.className]} class={[bem([theme]), className]}
style={{ width: addUnit(this.width) }} style={{ width: addUnit(width) }}
aria-labelledby={this.title || message} aria-labelledby={title || message}
{...{ {...{
...pick(this, [ ...pick(props, popupKeys),
'show', 'onUpdate:show': onUpdateShow,
'overlay',
'transition',
'lazyRender',
'closeOnPopstate',
'closeOnClickOverlay',
]),
'onUpdate:show': this.onUpdateShow,
}} }}
> >
{Title} {renderTitle()}
{this.genContent(title)} {renderContent()}
{this.theme === 'round-button' {theme === 'round-button' ? renderRoundButtons() : renderButtons()}
? this.genRoundButtons()
: this.genButtons()}
</Popup> </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,
}}
/>
);
}, },
}; };