UNPKG

choo-taro-ui-vue3

Version:

Taro UI Rewritten in Vue 3.0

214 lines (206 loc) 7.49 kB
import { defineComponent, ref, computed, reactive, watch, onMounted, toRef, nextTick, resolveComponent, normalizeStyle, createVNode, renderList, Fragment, openBlock, createElementBlock, withCtx, mergeProps, createBlock } from 'vue'; import { cssStringToObject, getEventDetail, delayQuerySelector } from '../utils'; import { useModelValue } from '../composables'; const AtRange = defineComponent({ name: "AtRange", emits: { "update:modelValue"(value) { return !!(value && Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number"); }, "after-change"(value) { return !!(value && Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number"); } }, props: { sliderStyle: { type: [Object, String], default: "" }, railStyle: { type: [Object, String], default: "" }, trackStyle: { type: [Object, String], default: "" }, modelValue: { type: Array, default: [0, 0] }, min: { type: Number, default: 0 }, max: { type: Number, default: 100 }, blockSize: { type: Number, default: 0 }, disabled: Boolean, onAfterChange: Function }, setup(props, { emit }) { const left = ref(0); const width = ref(0); const currentSlider = ref(""); const rangeValue = useModelValue(props, emit); const deltaValue = computed(() => props.max - props.min); const state = reactive({ aX: 0, bX: 0 }); const rootClasses = computed(() => ["at-range", { "at-range--disabled": props.disabled }]); const containerStyle = computed(() => ({ height: props.blockSize ? `${props.blockSize}PX` : "" })); const sliderCommonStyle = computed(() => ({ width: props.blockSize ? `${props.blockSize}PX` : "", height: props.blockSize ? `${props.blockSize}PX` : "", marginLeft: props.blockSize ? `${-props.blockSize / 2}PX` : "" })); const sliderAStyle = computed(() => ({ ...sliderCommonStyle.value, ...typeof props.sliderStyle === "string" ? cssStringToObject(props.sliderStyle) : props.sliderStyle, left: `${state.aX}%`, top: "0%" })); const sliderBStyle = computed(() => ({ ...sliderCommonStyle.value, ...typeof props.sliderStyle === "string" ? cssStringToObject(props.sliderStyle) : props.sliderStyle, left: `${state.bX}%`, top: "0%" })); const atTrackStyle = computed(() => ({ ...typeof props.trackStyle === "string" ? cssStringToObject(props.trackStyle) : props.trackStyle, left: `${Math.min(state.aX, state.bX)}%`, width: `${Math.abs(state.aX - state.bX)}%` })); function handleClick(event) { if (currentSlider.value && !props.disabled) { let sliderValue = 0; const detail = getEventDetail(event); sliderValue = detail.x - left.value; setSliderValue(currentSlider.value, sliderValue, "onChange"); } } function handleTouchmove(sliderName, event) { if (props.disabled) return; event.stopPropagation(); const clientX = event.touches[0].clientX; setSliderValue(sliderName, clientX - left.value, "onChange"); } function handleTouchend(sliderName) { if (props.disabled) return; currentSlider.value = sliderName; triggerEvent("onAfterChange"); } function setSliderValue(sliderName, targetValue, funcName) { const distance = Math.min(Math.max(targetValue, 0), width.value); const sliderValue = Math.floor(distance / width.value * 100); if (funcName) { state[sliderName] = sliderValue; nextTick(() => { triggerEvent(funcName); }); } else { state[sliderName] = sliderValue; } } function setValue(value) { const aX = Math.round((value[0] - props.min) / deltaValue.value * 100); const bX = Math.round((value[1] - props.min) / deltaValue.value * 100); state.aX = aX; state.bX = bX; } function triggerEvent(funcName) { const { aX, bX } = state; const a = Math.round(aX / 100 * deltaValue.value) + props.min; const b = Math.round(bX / 100 * deltaValue.value) + props.min; const result = [a, b].sort((x, y) => x - y); if (funcName === "onChange") { rangeValue.value = result; } else if (funcName === "onAfterChange") { emit("after-change", result); } } function updatePos() { delayQuerySelector(this, ".at-range__container", 10).then((rect) => { width.value = Math.round(rect[0].width); left.value = Math.round(rect[0].left); }); } watch(rangeValue, (value, prevValue) => { updatePos(); if (prevValue[0] !== value[0] || prevValue[1] !== value[1]) { setValue(value); } }); onMounted(() => { updatePos(); setValue(rangeValue.value); }); return { railStyle: toRef(props, "railStyle"), rootClasses, sliderAStyle, sliderBStyle, atTrackStyle, containerStyle, handleClick, handleTouchend, handleTouchmove }; } }); // Binding optimization for webpack code-split const _resolveComponent = resolveComponent, _normalizeStyle = normalizeStyle, _createVNode = createVNode, _renderList = renderList, _Fragment = Fragment, _openBlock = openBlock, _createElementBlock = createElementBlock, _withCtx = withCtx, _mergeProps = mergeProps, _createBlock = createBlock; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_taro_view = process.env.TARO_ENV === "h5" ? _resolveComponent("taro-view") : "view"; return (_openBlock(), _createBlock(_component_taro_view, _mergeProps(_ctx.$attrs, { class: _ctx.rootClasses, onTap: _ctx.handleClick }), { default: _withCtx(() => [ _createVNode(_component_taro_view, { class: "at-range__container", style: _normalizeStyle(_ctx.containerStyle) }, { default: _withCtx(() => [ _createVNode(_component_taro_view, { class: "at-range__rail", style: _normalizeStyle(_ctx.railStyle) }, { default: _withCtx(() => [ _createVNode(_component_taro_view, { class: "at-range__track", style: _normalizeStyle(_ctx.atTrackStyle) }, null, 8 /* PROPS */, ["style"]), (_openBlock(), _createElementBlock(_Fragment, null, _renderList(['aX', 'bX'], (sliderName, index) => { return _createVNode(_component_taro_view, { key: `${sliderName} - ${index}`, style: _normalizeStyle(sliderName === 'aX' ? _ctx.sliderAStyle : _ctx.sliderBStyle), class: "at-range__slider", onTouchend: $event => (_ctx.handleTouchend(sliderName)), onTouchmove: $event => (_ctx.handleTouchmove(sliderName, $event)) }, null, 8 /* PROPS */, ["style", "onTouchend", "onTouchmove"]) }), 64 /* STABLE_FRAGMENT */)) ]), _: 1 /* STABLE */ }, 8 /* PROPS */, ["style"]) ]), _: 1 /* STABLE */ }, 8 /* PROPS */, ["style"]) ]), _: 1 /* STABLE */ }, 16 /* FULL_PROPS */, ["class", "onTap"])) } AtRange.render = _sfc_render; export default AtRange;