refactor(Slider): refactor with composition api

This commit is contained in:
chenjiahan 2020-08-26 17:49:21 +08:00
parent c720eea831
commit 47a7ccef85

View File

@ -1,12 +1,18 @@
import { ref, computed } from 'vue';
import { createNamespace, addUnit } from '../utils'; import { createNamespace, addUnit } from '../utils';
import { preventDefault } from '../utils/dom/event'; import { preventDefault } from '../utils/dom/event';
import { TouchMixin } from '../mixins/touch';
// Mixins
import { FieldMixin } from '../mixins/field'; import { FieldMixin } from '../mixins/field';
// Composition
import { useRect } from '../composition/use-rect';
import { useTouch } from '../composition/use-touch';
const [createComponent, bem] = createNamespace('slider'); const [createComponent, bem] = createNamespace('slider');
export default createComponent({ export default createComponent({
mixins: [TouchMixin, FieldMixin], mixins: [FieldMixin],
props: { props: {
disabled: Boolean, disabled: Boolean,
@ -35,161 +41,162 @@ export default createComponent({
emits: ['change', 'drag-end', 'drag-start', 'update:modelValue'], emits: ['change', 'drag-end', 'drag-start', 'update:modelValue'],
data() { setup(props, { emit, slots }) {
return { let startValue;
dragStatus: '', let currentValue;
};
},
computed: { const rootRef = ref();
range() { const dragStatus = ref();
return this.max - this.min; const touch = useTouch();
},
buttonStyle() { const range = computed(() => props.max - props.min);
if (this.buttonSize) {
const size = addUnit(this.buttonSize); const buttonStyle = computed(() => {
if (props.buttonSize) {
const size = addUnit(props.buttonSize);
return { return {
width: size, width: size,
height: size, height: size,
}; };
} }
}, });
},
created() { const wrapperStyle = computed(() => {
// format initial value const crossAxis = props.vertical ? 'width' : 'height';
this.updateValue(this.modelValue); return {
}, background: props.inactiveColor,
[crossAxis]: addUnit(props.barHeight),
};
});
mounted() { const barStyle = computed(() => {
this.bindTouchEvent(this.$refs.wrapper); const mainAxis = props.vertical ? 'height' : 'width';
}, return {
[mainAxis]: `${((props.modelValue - props.min) * 100) / range.value}%`,
background: props.activeColor,
transition: dragStatus.value ? 'none' : null,
};
});
methods: { const format = (value) => {
onTouchStart(event) { const { min, max, step } = props;
if (this.disabled) { value = Math.max(min, Math.min(value, max));
return Math.round(value / step) * step;
};
const updateValue = (value, end) => {
value = format(value);
if (value !== props.modelValue) {
emit('update:modelValue', value);
}
if (end && value !== startValue) {
emit('change', value);
}
};
const onClick = (event) => {
event.stopPropagation();
if (props.disabled) {
return; return;
} }
this.touchStart(event); const { min, vertical, modelValue } = props;
this.startValue = this.format(this.modelValue); const rect = useRect(rootRef);
this.dragStatus = 'start'; const delta = vertical
}, ? event.clientY - rect.top
: event.clientX - rect.left;
const total = vertical ? rect.height : rect.width;
const value = +min + (delta / total) * range.value;
onTouchMove(event) { startValue = modelValue;
if (this.disabled) { updateValue(value, true);
};
const onTouchStart = (event) => {
if (props.disabled) {
return; return;
} }
if (this.dragStatus === 'start') { touch.start(event);
this.$emit('drag-start'); startValue = format(props.modelValue);
dragStatus.value = 'start';
};
const onTouchMove = (event) => {
if (props.disabled) {
return;
}
if (dragStatus.value === 'start') {
emit('drag-start');
} }
preventDefault(event, true); preventDefault(event, true);
this.touchMove(event); touch.move(event);
this.dragStatus = 'draging'; dragStatus.value = 'draging';
const rect = this.$el.getBoundingClientRect(); const rect = useRect(rootRef);
const delta = this.vertical ? this.deltaY : this.deltaX; const delta = props.vertical ? touch.deltaY.value : touch.deltaX.value;
const total = this.vertical ? rect.height : rect.width; const total = props.vertical ? rect.height : rect.width;
const diff = (delta / total) * this.range; const diff = (delta / total) * range.value;
this.newValue = this.startValue + diff; currentValue = startValue + diff;
this.updateValue(this.newValue); updateValue(currentValue);
}, };
onTouchEnd() { const onTouchEnd = () => {
if (this.disabled) { if (props.disabled) {
return; return;
} }
if (this.dragStatus === 'draging') { if (dragStatus.value === 'draging') {
this.updateValue(this.newValue, true); updateValue(currentValue, true);
this.$emit('drag-end'); emit('drag-end');
} }
this.dragStatus = ''; dragStatus.value = '';
},
onClick(event) {
event.stopPropagation();
if (this.disabled) return;
const rect = this.$el.getBoundingClientRect();
const delta = this.vertical
? event.clientY - rect.top
: event.clientX - rect.left;
const total = this.vertical ? rect.height : rect.width;
const value = +this.min + (delta / total) * this.range;
this.startValue = this.modelValue;
this.updateValue(value, true);
},
updateValue(value, end) {
value = this.format(value);
if (value !== this.modelValue) {
this.$emit('update:modelValue', value);
}
if (end && value !== this.startValue) {
this.$emit('change', value);
}
},
format(value) {
return (
Math.round(Math.max(this.min, Math.min(value, this.max)) / this.step) *
this.step
);
},
},
render() {
const { vertical } = this;
const mainAxis = vertical ? 'height' : 'width';
const crossAxis = vertical ? 'width' : 'height';
const wrapperStyle = {
background: this.inactiveColor,
[crossAxis]: addUnit(this.barHeight),
}; };
const barStyle = { const renderButton = () => (
[mainAxis]: `${((this.modelValue - this.min) * 100) / this.range}%`,
background: this.activeColor,
};
if (this.dragStatus) {
barStyle.transition = 'none';
}
return (
<div <div
style={wrapperStyle}
class={bem({ disabled: this.disabled, vertical })}
onClick={this.onClick}
>
<div class={bem('bar')} style={barStyle}>
<div
ref="wrapper"
role="slider" role="slider"
tabindex={this.disabled ? -1 : 0} tabindex={props.disabled ? -1 : 0}
aria-valuemin={this.min} aria-valuemin={props.min}
aria-valuenow={this.modelValue} aria-valuenow={props.modelValue}
aria-valuemax={this.max} aria-valuemax={props.max}
aria-orientation={this.vertical ? 'vertical' : 'horizontal'} aria-orientation={props.vertical ? 'vertical' : 'horizontal'}
class={bem('button-wrapper')} class={bem('button-wrapper')}
onTouchstart={onTouchStart}
onTouchmove={onTouchMove}
onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd}
> >
{this.$slots.button ? ( {slots.button ? (
this.$slots.button() slots.button()
) : ( ) : (
<div class={bem('button')} style={this.buttonStyle} /> <div class={bem('button')} style={buttonStyle.value} />
)} )}
</div> </div>
);
// format initial value
updateValue(props.modelValue);
return () => (
<div
ref={rootRef}
style={wrapperStyle.value}
class={bem({
vertical: props.vertical,
disabled: props.disabled,
})}
onClick={onClick}
>
<div class={bem('bar')} style={barStyle.value}>
{renderButton()}
</div> </div>
</div> </div>
); );