Ползунок у range input двигается неверно
Буду благодарен, подскажите, пожалуйста, почему ползунок двигается не синхронно с линией прогресса?
То есть при максимально раздвинутой линии прогресса все правильно отображается, но когда они стремятся друг к другу, ползунок постепенно начинает отставать от линии прогресса.
<template>
<div class="container">
<div class="slider">
<div class="slider__inner">
<div class="sliders_control">
<span :style="progressStyle" class="slider__progress"></span>
<input
ref="fromSlider"
v-model="fromValue"
id="fromSlider"
type="range"
min="0"
max="100"
:step="visibleMounth ? stepValue : stepValueYearAndMonth"
/>
<input
ref="toSlider"
v-model="toValue"
id="toSlider"
type="range"
min="0"
max="100"
:step="visibleMounth ? stepValue : stepValueYearAndMonth"
/>
</div>
<ul class="slider__year-list" v-if="visibleMounth">
<li
class="slider__year-item"
v-for="(months, year) in date"
:key="year"
>
<div class="slider__month">
{{ year }}
<template v-if="false">
<ul
class="slider__mouth-list"
v-for="(month, index) in months"
:key="index"
>
<li class="slider__mouth-item">{{ month }}</li>
</ul>
</template>
</div>
</li>
</ul>
<ul class="slider__year-list" v-if="!visibleMounth">
<li
class="slider__year-item"
v-for="(months, year) in dateYearAndMounth"
:key="year"
>
<div class="slider__month">
{{ year }}
<ul
class="slider__mouth-list"
v-for="(month, index) in months"
:key="index"
>
<li class="slider__mouth-item">{{ month }}</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch } from "vue";
const mouth = ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",];
const date = {
2014: mouth,
2015: mouth,
2016: mouth,
2017: mouth,
2018: mouth,
2019: mouth,
2020: mouth,
2021: mouth,
2022: mouth,
2023: mouth,
2030: [],
};
let dateYearAndMounth = {};
const fromSlider = ref(null);
const toSlider = ref(null);
const fromValue = ref(5);
const toValue = ref(70);
const visibleMounth = ref(true);
const stepValue = computed(() => {
const numberOfYears = Object.keys(date).length;
let numberOfMouth = 12;
const numberOfSteps = numberOfMouth * numberOfYears - 12 + numberOfYears;
console.log((numberOfSteps > 1 ? 100 / (numberOfSteps - 1) : 1).toFixed(0));
return (numberOfSteps > 1 ? 100 / (numberOfSteps - 1) : 1).toFixed(3);
});
const stepValueYearAndMonth = computed(() => {
const numberOfYears = Object.keys(dateYearAndMounth).length;
let numberOfMouth = 12;
const numberOfSteps = numberOfMouth * numberOfYears - 12 + numberOfYears;
return (numberOfSteps > 1 ? 100 / (numberOfSteps - 1) : 1).toFixed(3);
});
const progressStyle = computed(() => {
const left = fromValue.value;
const width = toValue.value - fromValue.value;
console.log(width);
return {
left: `${left}%`,
width: `${width}%`,
};
});
watch([fromValue, toValue], ([newFromValue, newToValue]) => {
if (+newFromValue > +newToValue) {
[fromValue.value, toValue.value] = [newToValue, newFromValue];
}
});
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 15px;
}
.slider {
display: flex;
width: 90%;
margin: 35% auto;
grid-gap: 20px;
align-items: center;
}
.slider__text-date {
width: 100px;
}
.slider__text {
margin-bottom: 10px;
}
.slider__inner {
width: 100%;
}
.sliders_control {
position: relative;
min-height: 50px;
display: flex;
align-items: center;
}
.slider__progress {
position: absolute;
width: 100%;
height: 10px;
background-color: #5cadea;
z-index: 1;
}
input[type="range"] {
appearance: none;
height: 10px;
width: 100%;
position: absolute;
background-color: #edf1f1;
pointer-events: none;
left: 0;
right: 0;
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
position: relative;
pointer-events: all;
width: 20px;
height: 20px;
background-color: #5cadea;
border-radius: 50%;
z-index: 2;
cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb::after {
display: flex;
align-items: center;
width: 10px;
height: 10px;
background-color: #152121;
position: absolute;
z-index: 4;
}
#fromSlider::-webkit-slider-thumb {
transform: translateX(-30%);
}
#toSlider::-webkit-slider-thumb {
transform: translateX(20%);
}
#fromSlider {
height: 0;
z-index: 2;
}
.slider__year-list {
display: flex;
justify-content: space-between;
width: 102%;
margin-left: -8px;
}
.slider__year-item:not(:last-child) {
width: 100%;
margin-right: 10px;
}
.slider__month {
display: flex;
justify-content: space-between;
}
</style>
Ответы (1 шт):
Могу точно сказать, что это где-то твой косяк в вычислениях смещений элемента. (Сначала думал что браузерный, но нет) https://codesandbox.io/p/sandbox/rang-fn468d
<template>
<div class="container">
<div class="slider">
<div class="slider__inner">
<div class="sliders_control">
<span :style="progressStyle" class="slider__progress"></span>
<input
ref="fromSlider"
v-model="fromValue"
id="fromSlider"
type="range"
min="0"
max="100"
:step="visibleMounth ? stepValue : stepValueYearAndMonth"
/>
<input
ref="toSlider"
v-model="toValue"
id="toSlider"
type="range"
min="0"
max="100"
:step="visibleMounth ? stepValue : stepValueYearAndMonth"
/>
</div>
<ul class="slider__year-list" v-if="visibleMounth">
<li
class="slider__year-item"
v-for="(months, year) in date"
:key="year"
>
<div class="slider__month">
{{ year }}
<template v-if="false">
<ul
class="slider__mouth-list"
v-for="(month, index) in months"
:key="index"
>
<li class="slider__mouth-item">{{ month }}</li>
</ul>
</template>
</div>
</li>
</ul>
<ul class="slider__year-list" v-if="!visibleMounth">
<li
class="slider__year-item"
v-for="(months, year) in dateYearAndMounth"
:key="year"
>
<div class="slider__month">
{{ year }}
<ul
class="slider__mouth-list"
v-for="(month, index) in months"
:key="index"
>
<li class="slider__mouth-item">{{ month }}</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch } from "vue";
const mouth = ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",];
const date = {
2014: mouth,
2015: mouth,
2016: mouth,
2017: mouth,
2018: mouth,
2019: mouth,
2020: mouth,
2021: mouth,
2022: mouth,
2023: mouth,
2030: [],
};
let dateYearAndMounth = {};
const fromSlider = ref(null);
const toSlider = ref(null);
const fromValue = ref(5);
const toValue = ref(70);
const visibleMounth = ref(true);
const stepValue = computed(() => {
const numberOfYears = Object.keys(date).length;
let numberOfMouth = 12;
const numberOfSteps = numberOfMouth * numberOfYears - 12 + numberOfYears;
console.log((numberOfSteps > 1 ? 100 / (numberOfSteps - 1) : 1).toFixed(0));
return (numberOfSteps > 1 ? 100 / (numberOfSteps - 1) : 1).toFixed(3);
});
const stepValueYearAndMonth = computed(() => {
const numberOfYears = Object.keys(dateYearAndMounth).length;
let numberOfMouth = 12;
const numberOfSteps = numberOfMouth * numberOfYears - 12 + numberOfYears;
return (numberOfSteps > 1 ? 100 / (numberOfSteps - 1) : 1).toFixed(3);
});
const progressStyle = computed(() => {
const left = fromValue.value - 0.98;
const width = toValue.value - fromValue.value;
console.log(width);
return {
left: `${left}%`,
width: `${width}%`,
};
});
watch([fromValue, toValue], ([newFromValue, newToValue]) => {
if (+newFromValue > +newToValue) {
[fromValue.value, toValue.value] = [newToValue, newFromValue];
}
});
</script>
<style scoped>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 15px;
}
.slider {
display: flex;
width: 90%;
margin: 35% auto;
grid-gap: 20px;
align-items: center;
}
.slider__text-date {
width: 100px;
}
.slider__text {
margin-bottom: 10px;
}
.slider__inner {
width: 100%;
}
.sliders_control {
position: relative;
min-height: 50px;
display: flex;
align-items: center;
}
.slider__progress {
position: absolute;
width: 100%;
height: 10px;
background-color: #5cadea;
z-index: 1;
}
input[type="range"] {
appearance: none;
height: 10px;
width: 100%;
position: absolute;
background-color: #edf1f1;
pointer-events: none;
left: 0;
right: 0;
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
position: relative;
pointer-events: all;
width: 20px;
height:20px;
background-color: #5cadea;
border-radius: 50%;
z-index: 2;
cursor: pointer;
}
#fromSlider::-webkit-slider-thumb {
transform: translateX(-30%);
}
#toSlider::-webkit-slider-thumb {
transform: translateX(20%);
}
#fromSlider {
height: 0;
z-index: 2;
}
.slider__year-list {
display: flex;
justify-content: space-between;
width: 102%;
margin-left: -8px;
}
.slider__year-item:not(:last-child) {
width: 100%;
margin-right: 10px;
}
.slider__month {
display: flex;
justify-content: space-between;
}
</style>
Я решил вот этой корректировкой const left = fromValue.value - 0.98;
но теперь там сначала этот ползунок вылазит и атрибут step
у тебя не очень хороший, там желательно цельные числа передовать.
Вообщем проблема в параметрах а не в стилях.