refactor(NumberKeyboard): refactor with composition api

This commit is contained in:
chenjiahan 2020-09-10 17:42:43 +08:00
parent ad5980c914
commit 14c1d4ea77

View File

@ -1,20 +1,12 @@
import { Teleport, Transition } from 'vue'; import { ref, watch, computed, Teleport, Transition } from 'vue';
import { createNamespace } from '../utils'; import { createNamespace } from '../utils';
import { stopPropagation } from '../utils/dom/event'; import { stopPropagation } from '../utils/dom/event';
import { BindEventMixin } from '../mixins/bind-event'; import { useClickOutside } from '../composition/use-click-outside';
import Key from './Key'; import Key from './Key';
const [createComponent, bem] = createNamespace('number-keyboard'); const [createComponent, bem] = createNamespace('number-keyboard');
export default createComponent({ export default createComponent({
mixins: [
BindEventMixin(function (bind) {
if (this.hideOnClickOutside) {
bind(document.body, 'touchstart', this.onBlur);
}
}),
],
props: { props: {
show: Boolean, show: Boolean,
title: String, title: String,
@ -67,47 +59,30 @@ export default createComponent({
'update:modelValue', 'update:modelValue',
], ],
watch: { setup(props, { emit, slots }) {
show(val) { const rootRef = ref();
if (!this.transition) {
this.$emit(val ? 'show' : 'hide');
}
},
},
computed: { const genBasicKeys = () => {
keys() {
if (this.theme === 'custom') {
return this.genCustomKeys();
}
return this.genDefaultKeys();
},
},
methods: {
genBasicKeys() {
const keys = []; const keys = [];
for (let i = 1; i <= 9; i++) { for (let i = 1; i <= 9; i++) {
keys.push({ text: i }); keys.push({ text: i });
} }
return keys; return keys;
}, };
genDefaultKeys() { const genDefaultKeys = () => [
return [ ...genBasicKeys(),
...this.genBasicKeys(), { text: props.extraKey, type: 'extra' },
{ text: this.extraKey, type: 'extra' }, { text: 0 },
{ text: 0 }, {
{ text: props.showDeleteKey ? props.deleteButtonText : '',
text: this.showDeleteKey ? this.deleteButtonText : '', type: props.showDeleteKey ? 'delete' : '',
type: this.showDeleteKey ? 'delete' : '', },
}, ];
];
},
genCustomKeys() { const genCustomKeys = () => {
const keys = this.genBasicKeys(); const keys = genBasicKeys();
const { extraKey } = this; const { extraKey } = props;
const extraKeys = Array.isArray(extraKey) ? extraKey : [extraKey]; const extraKeys = Array.isArray(extraKey) ? extraKey : [extraKey];
if (extraKeys.length === 1) { if (extraKeys.length === 1) {
@ -124,47 +99,53 @@ export default createComponent({
} }
return keys; return keys;
}, };
onBlur() { const keys = computed(() =>
this.show && this.$emit('blur'); props.theme === 'custom' ? genCustomKeys() : genDefaultKeys()
}, );
onClose() { const onBlur = () => {
this.$emit('close'); if (props.show) {
this.onBlur(); emit('blur');
}, }
};
onAnimationEnd() { const onClose = () => {
this.$emit(this.show ? 'show' : 'hide'); emit('close');
}, onBlur();
};
onPress(text, type) { const onAnimationEnd = () => {
emit(props.show ? 'show' : 'hide');
};
const onPress = (text, type) => {
if (text === '') { if (text === '') {
if (type === 'extra') { if (type === 'extra') {
this.onBlur(); onBlur();
} }
return; return;
} }
const value = this.modelValue; const value = props.modelValue;
if (type === 'delete') { if (type === 'delete') {
this.$emit('delete'); emit('delete');
this.$emit('update:modelValue', value.slice(0, value.length - 1)); emit('update:modelValue', value.slice(0, value.length - 1));
} else if (type === 'close') { } else if (type === 'close') {
this.onClose(); onClose();
} else if (value.length < this.maxlength) { } else if (value.length < props.maxlength) {
this.$emit('input', text); emit('input', text);
this.$emit('update:modelValue', value + text); emit('update:modelValue', value + text);
} }
}, };
genTitle() { const renderTitle = () => {
const { title, theme, closeButtonText } = this; const { title, theme, closeButtonText } = props;
const titleLeft = this.$slots['title-left']; const leftSlot = slots['title-left'];
const showClose = closeButtonText && theme === 'default'; const showClose = closeButtonText && theme === 'default';
const showTitle = title || showClose || titleLeft; const showTitle = title || showClose || leftSlot;
if (!showTitle) { if (!showTitle) {
return; return;
@ -172,26 +153,26 @@ export default createComponent({
return ( return (
<div class={bem('header')}> <div class={bem('header')}>
{titleLeft && <span class={bem('title-left')}>{titleLeft}</span>} {leftSlot && <span class={bem('title-left')}>{leftSlot()}</span>}
{title && <h2 class={bem('title')}>{title}</h2>} {title && <h2 class={bem('title')}>{title}</h2>}
{showClose && ( {showClose && (
<button type="button" class={bem('close')} onClick={this.onClose}> <button type="button" class={bem('close')} onClick={onClose}>
{closeButtonText} {closeButtonText}
</button> </button>
)} )}
</div> </div>
); );
}, };
genKeys() { const renderKeys = () => {
return this.keys.map((key) => { return keys.value.map((key) => {
const slots = {}; const slots = {};
if (key.type === 'delete') { if (key.type === 'delete') {
slots.default = this.$slots.delete; slots.default = slots.delete;
} }
if (key.type === 'extra') { if (key.type === 'extra') {
slots.default = this.$slots['extra-key']; slots.default = slots['extra-key'];
} }
return ( return (
@ -202,64 +183,83 @@ export default createComponent({
type={key.type} type={key.type}
wider={key.wider} wider={key.wider}
color={key.color} color={key.color}
onPress={this.onPress} onPress={onPress}
/> />
); );
}); });
}, };
genSidebar() { const renderSidebar = () => {
if (this.theme === 'custom') { if (props.theme === 'custom') {
return ( return (
<div class={bem('sidebar')}> <div class={bem('sidebar')}>
{this.showDeleteKey && ( {props.showDeleteKey && (
<Key <Key
v-slots={{ delete: this.$slots.delete }} v-slots={{ delete: slots.delete }}
large large
text={this.deleteButtonText} text={props.deleteButtonText}
type="delete" type="delete"
onPress={this.onPress} onPress={onPress}
/> />
)} )}
<Key <Key
large large
text={this.closeButtonText} text={props.closeButtonText}
type="close" type="close"
color="blue" color="blue"
loading={this.closeButtonLoading} loading={props.closeButtonLoading}
onPress={this.onPress} onPress={onPress}
/> />
</div> </div>
); );
} }
}, };
},
render() { watch(
const Title = this.genTitle(); () => props.show,
const Content = ( (value) => {
<Transition name={this.transition ? 'van-slide-up' : ''}> if (!props.transition) {
<div emit(value ? 'show' : 'hide');
vShow={this.show} }
style={{ zIndex: this.zIndex }} }
class={bem({ unfit: !this.safeAreaInsetBottom, 'with-title': Title })}
onTouchstart={stopPropagation}
onAnimationend={this.onAnimationEnd}
onWebkitAnimationEnd={this.onAnimationEnd}
>
{Title}
<div class={bem('body')}>
<div class={bem('keys')}>{this.genKeys()}</div>
{this.genSidebar()}
</div>
</div>
</Transition>
); );
if (this.teleport) { useClickOutside({
return <Teleport to={this.teleport}>{Content}</Teleport>; event: 'touchstart',
} element: rootRef,
callback: onClose,
});
return Content; return () => {
const Title = renderTitle();
const Content = (
<Transition name={props.transition ? 'van-slide-up' : ''}>
<div
ref={rootRef}
vShow={props.show}
style={{ zIndex: props.zIndex }}
class={bem({
unfit: !props.safeAreaInsetBottom,
'with-title': !!Title,
})}
onTouchstart={stopPropagation}
onAnimationend={onAnimationEnd}
onWebkitAnimationEnd={onAnimationEnd}
>
{Title}
<div class={bem('body')}>
<div class={bem('keys')}>{renderKeys()}</div>
{renderSidebar()}
</div>
</div>
</Transition>
);
if (props.teleport) {
return <Teleport to={props.teleport}>{Content}</Teleport>;
}
return Content;
};
}, },
}); });