|
|
@@ -1,7 +1,13 @@
|
|
|
<template>
|
|
|
- <view class="nut-range-container">
|
|
|
+ <view :class="containerClasses">
|
|
|
<view class="min" v-if="!hiddenRange">{{ +min }}</view>
|
|
|
<view ref="root" :id="'root-' + refRandomId" :style="wrapperStyle" :class="classes" @click.stop="onClick">
|
|
|
+ <view class="nut-range-mark" v-if="marksList.length > 0">
|
|
|
+ <span v-for="marks in marksList" :key="marks" :class="markClassName(marks)" :style="marksStyle(marks)">
|
|
|
+ {{ marks }}
|
|
|
+ <span class="nut-range-tick" :style="tickStyle(marks)"></span>
|
|
|
+ </span>
|
|
|
+ </view>
|
|
|
<view class="nut-range-bar" :style="barStyle">
|
|
|
<template v-if="range">
|
|
|
<view
|
|
|
@@ -12,6 +18,7 @@
|
|
|
'nut-range-button-wrapper-left': index == 0,
|
|
|
'nut-range-button-wrapper-right': index == 1
|
|
|
}"
|
|
|
+ :catch-move="true"
|
|
|
:tabindex="disabled ? -1 : 0"
|
|
|
:aria-valuemin="+min"
|
|
|
:aria-valuenow="curValue(index)"
|
|
|
@@ -46,6 +53,7 @@
|
|
|
:aria-valuenow="curValue()"
|
|
|
:aria-valuemax="+max"
|
|
|
aria-orientation="horizontal"
|
|
|
+ :catch-move="true"
|
|
|
@touchstart.stop.prevent="
|
|
|
(e) => {
|
|
|
onTouchStart(e);
|
|
|
@@ -87,6 +95,14 @@ export default create({
|
|
|
activeColor: String,
|
|
|
inactiveColor: String,
|
|
|
buttonColor: String,
|
|
|
+ vertical: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ marks: {
|
|
|
+ type: Object,
|
|
|
+ default: {}
|
|
|
+ },
|
|
|
hiddenRange: {
|
|
|
type: Boolean,
|
|
|
default: false
|
|
|
@@ -124,6 +140,16 @@ export default create({
|
|
|
const dragStatus = ref<'start' | 'draging' | ''>();
|
|
|
const touch = useTouch();
|
|
|
|
|
|
+ const marksList = computed(() => {
|
|
|
+ const { marks, max, min } = props;
|
|
|
+ const marksKeys = Object.keys(marks);
|
|
|
+ const range = Number(max) - Number(min);
|
|
|
+ const list = marksKeys
|
|
|
+ .map(parseFloat)
|
|
|
+ .sort((a, b) => a - b)
|
|
|
+ .filter((point) => point >= min && point <= max);
|
|
|
+ return list;
|
|
|
+ });
|
|
|
const scope = computed(() => Number(props.max) - Number(props.min));
|
|
|
|
|
|
const classes = computed(() => {
|
|
|
@@ -131,10 +157,17 @@ export default create({
|
|
|
return {
|
|
|
[prefixCls]: true,
|
|
|
[`${prefixCls}-disabled`]: props.disabled,
|
|
|
+ [`${prefixCls}-vertical`]: props.vertical,
|
|
|
[`${prefixCls}-show-number`]: !props.hiddenRange
|
|
|
};
|
|
|
});
|
|
|
-
|
|
|
+ const containerClasses = computed(() => {
|
|
|
+ const prefixCls = 'nut-range-container';
|
|
|
+ return {
|
|
|
+ [prefixCls]: true,
|
|
|
+ [`${prefixCls}-vertical`]: props.vertical
|
|
|
+ };
|
|
|
+ });
|
|
|
const wrapperStyle = computed(() => {
|
|
|
return {
|
|
|
background: props.inactiveColor
|
|
|
@@ -166,14 +199,68 @@ export default create({
|
|
|
};
|
|
|
|
|
|
const barStyle = computed<CSSProperties>(() => {
|
|
|
+ if (props.vertical) {
|
|
|
+ return {
|
|
|
+ height: calcMainAxis(),
|
|
|
+ top: calcOffset(),
|
|
|
+ background: props.activeColor,
|
|
|
+ transition: dragStatus.value ? 'none' : undefined
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ width: calcMainAxis(),
|
|
|
+ left: calcOffset(),
|
|
|
+ background: props.activeColor,
|
|
|
+ transition: dragStatus.value ? 'none' : undefined
|
|
|
+ };
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const markClassName = (mark: any) => {
|
|
|
+ const classPrefix = 'nut-range-mark';
|
|
|
+ const { modelValue, max, min } = props;
|
|
|
+ let lowerBound: any = Number(min);
|
|
|
+ let upperBound: any = Number(max);
|
|
|
+ if (props.range) {
|
|
|
+ const [left, right] = modelValue as any;
|
|
|
+ lowerBound = left;
|
|
|
+ upperBound = right;
|
|
|
+ } else {
|
|
|
+ upperBound = modelValue;
|
|
|
+ }
|
|
|
+ let isActive = mark <= upperBound && mark >= lowerBound;
|
|
|
return {
|
|
|
- width: calcMainAxis(),
|
|
|
- left: calcOffset(),
|
|
|
- background: props.activeColor,
|
|
|
- transition: dragStatus.value ? 'none' : undefined
|
|
|
+ [`${classPrefix}-text`]: true,
|
|
|
+ [`${classPrefix}-text-active`]: isActive
|
|
|
+ };
|
|
|
+ };
|
|
|
+ const marksStyle = (mark: any) => {
|
|
|
+ const { max, min, vertical } = props;
|
|
|
+ let style: any = {
|
|
|
+ left: `${((mark - Number(min)) / scope.value) * 100}%`
|
|
|
+ };
|
|
|
+ if (vertical) {
|
|
|
+ style = {
|
|
|
+ top: `${((mark - Number(min)) / scope.value) * 100}%`
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return style;
|
|
|
+ };
|
|
|
+ const tickStyle = (mark: any) => {
|
|
|
+ const { modelValue, max, min } = props;
|
|
|
+ let lowerBound: any = Number(min);
|
|
|
+ let upperBound: any = Number(max);
|
|
|
+ if (props.range) {
|
|
|
+ const [left, right] = modelValue as any;
|
|
|
+ lowerBound = left;
|
|
|
+ upperBound = right;
|
|
|
+ }
|
|
|
+ let isActive = mark <= upperBound && mark >= lowerBound;
|
|
|
+ let style: any = {
|
|
|
+ background: !isActive ? props.inactiveColor : props.activeColor
|
|
|
};
|
|
|
- });
|
|
|
|
|
|
+ return style;
|
|
|
+ };
|
|
|
const format = (value: number) => {
|
|
|
const { min, max, step } = props;
|
|
|
value = Math.max(+min, Math.min(value, +max));
|
|
|
@@ -213,8 +300,14 @@ export default create({
|
|
|
|
|
|
const { min, modelValue } = props;
|
|
|
const rect = await useTaroRect(root, Taro);
|
|
|
- const delta = (event as any).touches[0].clientX - rect.left;
|
|
|
- const total = rect.width;
|
|
|
+ let delta = (event as any).touches[0].clientX - rect.left;
|
|
|
+ let total = rect.width;
|
|
|
+ console.log(delta);
|
|
|
+ console.log(total);
|
|
|
+ if (props.vertical) {
|
|
|
+ delta = (event as any).touches[0].clientY - rect.top;
|
|
|
+ total = rect.height;
|
|
|
+ }
|
|
|
const value = Number(min) + (delta / total) * scope.value;
|
|
|
if (isRange(modelValue)) {
|
|
|
const [left, right] = modelValue;
|
|
|
@@ -244,6 +337,8 @@ export default create({
|
|
|
}
|
|
|
|
|
|
dragStatus.value = 'start';
|
|
|
+ event.stopPropagation();
|
|
|
+ event.preventDefault();
|
|
|
};
|
|
|
|
|
|
const onTouchMove = async (event: TouchEvent) => {
|
|
|
@@ -259,22 +354,25 @@ export default create({
|
|
|
dragStatus.value = 'draging';
|
|
|
|
|
|
const rect = await useTaroRect(root, Taro);
|
|
|
- const delta = touch.deltaX.value;
|
|
|
- const total = rect.width;
|
|
|
- const diff = (delta / total) * scope.value;
|
|
|
-
|
|
|
+ let delta = touch.deltaX.value;
|
|
|
+ let total = rect.width;
|
|
|
+ let diff = (delta / total) * scope.value;
|
|
|
+ if (props.vertical) {
|
|
|
+ delta = touch.deltaY.value;
|
|
|
+ total = rect.height;
|
|
|
+ diff = (delta / total) * scope.value;
|
|
|
+ }
|
|
|
if (isRange(startValue)) {
|
|
|
(currentValue as number[])[buttonIndex.value] = startValue[buttonIndex.value] + diff;
|
|
|
} else {
|
|
|
currentValue = startValue + diff;
|
|
|
}
|
|
|
updateValue(currentValue);
|
|
|
-
|
|
|
event.stopPropagation();
|
|
|
event.preventDefault();
|
|
|
};
|
|
|
|
|
|
- const onTouchEnd = () => {
|
|
|
+ const onTouchEnd = (event: TouchEvent) => {
|
|
|
if (props.disabled) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -283,15 +381,15 @@ export default create({
|
|
|
emit('drag-end');
|
|
|
}
|
|
|
dragStatus.value = '';
|
|
|
+ event.stopPropagation();
|
|
|
+ event.preventDefault();
|
|
|
};
|
|
|
|
|
|
const curValue = (idx?: number) => {
|
|
|
const value = typeof idx === 'number' ? (props.modelValue as number[])[idx] : props.modelValue;
|
|
|
return value;
|
|
|
};
|
|
|
-
|
|
|
const refRandomId = Math.random().toString(36).slice(-8);
|
|
|
-
|
|
|
return {
|
|
|
root,
|
|
|
classes,
|
|
|
@@ -305,6 +403,11 @@ export default create({
|
|
|
barStyle,
|
|
|
curValue,
|
|
|
buttonIndex,
|
|
|
+ containerClasses,
|
|
|
+ markClassName,
|
|
|
+ marksStyle,
|
|
|
+ marksList,
|
|
|
+ tickStyle,
|
|
|
refRandomId
|
|
|
};
|
|
|
}
|