choo-taro-ui-vue3
Version:
Taro UI Rewritten in Vue 3.0
214 lines (206 loc) • 7.49 kB
JavaScript
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;