import { defineComponent, ref, watch, reactive, onMounted, computed } from 'vue' import { useMouseInElement, useMousePressed } from '@vueuse/core' const slider = defineComponent({ name: 'slider', props: { value: { type: [Number, Array], }, range: { type: Boolean, default: false, }, max: { type: Number, default: 100, }, min: { type: Number, default: 0, }, }, emits: ['update:value'], setup(props, { slots, emit }) { const sliderRef = ref(null) const { elementWidth: sliderWidth, elementX: sliderX } = useMouseInElement(sliderRef) const pointOneRef = ref(null) const { pressed: one } = useMousePressed({ target: pointOneRef }) const pointTwoRef = ref(null) const { pressed: two } = useMousePressed({ target: pointTwoRef }) const pointOneStyle = reactive({ left: 0, }) const pointTwoStyle = reactive({ left: 0, display: props.range ? 'block' : 'none', }) const trackStyle = reactive({ left: 0, 'max-width': 0, }) const leftRecord = reactive({ one: 0, two: 0, }) onMounted(() => { const { width } = sliderRef.value.getBoundingClientRect() const rateTransform = (value) => { return (1 / (props.max - props.min)) * value * width } if (props.range) { leftRecord.one = rateTransform(props.value[0]) leftRecord.two = rateTransform(props.value[1]) pointOneStyle.left = rateTransform(props.value[0]) + 'px' pointTwoStyle.left = rateTransform(props.value[1]) + 'px' } else { leftRecord.one = rateTransform(props.value) pointOneStyle.left = rateTransform(props.value) + 'px' } }) const ceilTransform = (value) => { return ( Math.ceil((value / sliderWidth.value) * (props.max - props.min)) + props.min ) } const floorTransform = (value) => { return ( Math.floor((value / sliderWidth.value) * (props.max - props.min)) + props.min ) } watch([one, two, sliderX], ([oneIsPress, twoIsPress]) => { if ( oneIsPress && sliderX.value >= 0 && sliderX.value <= sliderWidth.value ) { if (props.range) { const val1 = leftRecord.one < sliderWidth.value / 2 ? floorTransform(leftRecord.one) : ceilTransform(leftRecord.one) const val2 = leftRecord.two < sliderWidth.value / 2 ? floorTransform(leftRecord.two) : ceilTransform(leftRecord.two) const value = val1 > val2 ? [val2, val1] : [val1, val2] emit('update:value', value) } else { if (leftRecord.one < sliderWidth.value / 2) { emit('update:value', floorTransform(leftRecord.one)) } else { emit('update:value', ceilTransform(leftRecord.one)) } } leftRecord.one = sliderX.value pointOneStyle.left = sliderX.value - 7 + 'px' } if ( twoIsPress && sliderX.value >= 0 && sliderX.value <= sliderWidth.value ) { leftRecord.two = sliderX.value pointTwoStyle.left = sliderX.value - 7 + 'px' if (props.range) { const val1 = leftRecord.one < sliderWidth.value / 2 ? floorTransform(leftRecord.one) : ceilTransform(leftRecord.one) const val2 = leftRecord.two < sliderWidth.value / 2 ? floorTransform(leftRecord.two) : ceilTransform(leftRecord.two) const value = val1 > val2 ? [val2, val1] : [val1, val2] emit('update:value', value) } else { if (leftRecord.one < sliderWidth.value / 2) { emit('update:value', floorTransform(leftRecord.one)) } else { emit('update:value', ceilTransform(leftRecord.one)) } } } if (leftRecord.one > leftRecord.two) { trackStyle.left = leftRecord.two + 'px' trackStyle['max-width'] = leftRecord.one - leftRecord.two + 'px' } else { trackStyle.left = leftRecord.one + 'px' trackStyle['max-width'] = leftRecord.two - leftRecord.one + 'px' } }) return () => (
) }, }) export default slider