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