mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-24 02:16:12 +08:00
refactor(Slider): refactor with composition api
This commit is contained in:
parent
c720eea831
commit
47a7ccef85
@ -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>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user