У меня есть ползунок цен и два входа для минимальной и максимальной цены. У меня есть небольшой баг. Когда я пытаюсь ввести другое значение в поле минимальной цены и начинаю стирать предыдущее, оно сразу меняется на 50 (наименьшее значение ползунка цены), и только после того, как вход «переключится», я могу ввести новую минимальную цену. .
Я использую многодиапазонный слайдер от Developergovindgupta.
Вот как этот код работает на данный момент: https://streamable.com/r9rfsh.
Вот мой ценовой слайдер с входными данными:
<script setup>
import { computed, ref, reactive, watch } from "vue";
import { useVuelidate } from "@vuelidate/core";
import { minValue, maxValue } from "@vuelidate/validators";
import MultiRangeSlider from "multi-range-slider-vue";
const props = defineProps({
listPrice: {
type: Object
},
modelValue: {
type: Object
},
})
const emit = defineEmits(["update:modelValue"])
function updatePrice(e) {
valsPrices.min = e.minValue;
valsPrices.max = e.maxValue;
}
const rangeMargin = 50;
const listPrices = reactive(JSON.parse(JSON.stringify(props.listPrice)))
const valsPrices = reactive(JSON.parse(JSON.stringify(props.modelValue)))
const rules = computed(() => ({
min: {
minValue: minValue(listPrices.min),
maxValue: maxValue(
((valsPrices.max - rangeMargin) >= listPrices.min) ?
valsPrices.max - rangeMargin :
listPrices.min
)
},
max: {
minValue: minValue(
((valsPrices.min + rangeMargin) <= listPrices.max) ?
valsPrices.min + rangeMargin :
listPrices.max
),
maxValue: maxValue(listPrices.max)
},
}))
const v = useVuelidate(rules, valsPrices)
function cleanMinPrice() {
if (v.value.min.minValue.$invalid) {
valsPrices.min = listPrices.min
console.info(v.value.min.$model)
}
if (v.value.min.maxValue.$invalid) {
valsPrices.min = valsPrices.max - rangeMargin
}
}
function cleanMaxPrice() {
console.info(valsPrices.max)
if (v.value.max.minValue.$invalid) {
valsPrices.max = valsPrices.min + rangeMargin
}
if (v.value.max.maxValue.$invalid) {
valsPrices.max = listPrices.max
}
}
watch(valsPrices, async (val) => {
emit("update:modelValue", val);
}, {
deep: true,
immediate: true
})
</script>
<template>
<h6>Price</h6>
<div class = "d-flex justify-content-between">
<div class = "d-flex align-items-center">
<label for = "minPrice" class = "form-label m-0">Min: </label>
<input type = "number"
class = "form-control form-control-sm"
id = "minPrice"
v-model = "v.min.$model"
@blur = "cleanMinPrice">
</div>
<div class = "d-flex align-items-center">
<label for = "maxPrice" class = "form-label m-0">Max: </label>
<input type = "number"
class = "form-control form-control-sm"
id = "maxPrice"
v-model = "v.max.$model"
@blur = "cleanMaxPrice">
</div>
</div>
<MultiRangeSlider
baseClassName = "multi-range-slider"
:min = "props.listPrice.min"
:max = "props.listPrice.max"
:minValue = "valsPrices.min"
:maxValue = "valsPrices.max"
:ruler = "false"
:rangeMargin = "rangeMargin"
@input = "updatePrice"
/>
</template>
Вот как компонент используется внутри компонента фильтра:
<script setup>
import {reactive, watch} from "vue";
import PriceSlider from "./PriceSlider.vue";
const props = defineProps({
filterList: Object,
modelValue: Object,
loading: Boolean,
})
const emit = defineEmits(["filter", "update:modelValue"])
let filterVals = reactive(JSON.parse(JSON.stringify(props.modelValue)))
watch(
filterVals,
(value) => {
emit("update:modelValue", value);
},
{ deep: true, immediate: true }
)
</script>
<template>
<section class = "col-3">
...
<div class = "mb-3">
<h3 class = "fs-3">Price</h3>
<PriceSlider
:listPrice = "filterList.price"
v-model = "filterVals.price" />
</div>
</section>
</template>
Это filterList и filterValues, которые я передаю слайдеру на Products.vue — странице, где отображаются продукты. filterList содержит все возможные значения фильтра, такие как все цвета, категории, а также наименьшее и наибольшее значения ползунка цен. filterVals содержит параметры фильтра, выбранные пользователем.
const filterList = reactive({
price: {
min: 50,
max: 900
}
})
const filterValues = reactive({
price: {
min: 80,
max: 600
}
})
Они объявлены внутри компонента Products.vue. Вот как компонент фильтра используется на странице продуктов.
<script setup>
import HeaderOther from "../components/layout/HeaderOther.vue";
import Filter from "../components/Products/Filter.vue";
import { reactive } from "vue";
const filterList = reactive({
price: {
min: 50,
max: 900
}
})
const filterValues = reactive({
price: {
min: 80,
max: 600
}
})
function getFilterResults() {
console.info(filterValues.value)
}
</script>
<template>
<div class = "container-fluid">
<HeaderOther></HeaderOther>
<div class = "row mw-2000 mx-5 my-0">
<Filter :filterList = "filterList"
v-model = "filterValues"
@filter = "getFilterResults" />
</div>
</div>
</template>
Я обнаружил, что проблема заключается в функции, которая обновляет минимальную и максимальную цену при перетаскивании ползунка:
<script setup>
...
function updatePrice(e) {
valsPrices.min = e.minValue;
valsPrices.max = e.maxValue;
}
...
</script>
<template>
...
<MultiRangeSlider
baseClassName = "multi-range-slider"
:min = "props.listPrice.min"
:max = "props.listPrice.max"
:minValue = "valsPrices.min"
:maxValue = "valsPrices.max"
:ruler = "false"
:rangeMargin = "rangeMargin"
@input = "updatePrice"
/>
</template>
Но я не знаю, что делать, чтобы решить эту проблему. Заранее спасибо!
ОБНОВЛЕНИЕ 1
К сожалению, после изменения события появилась еще одна проблема. valsPrice.min и valsPrice.max не меняются при перетаскивании большого пальца. Сейчас это выглядит так: https://streamable.com/vg8feh.
Теперь это компонент MultiRangeSlider:
<MultiRangeSlider
baseClassName = "multi-range-slider"
:min = "props.listPrice.min"
:max = "props.listPrice.max"
:minValue = "valsPrices.min"
:maxValue = "valsPrices.max"
:ruler = "false"
:rangeMargin = "rangeMargin"
@keyDown = "updatePrice"
/>





Вы можете просто изменить событие input на keyDown или change. Также я думаю, что вам не нужны какие-либо события, поскольку вы используете наблюдатели, поэтому ваши значения будут автоматически обновляться при минимальном и максимальном изменении.
Я попробовал ваш код, и он работает нормально в обоих случаях. Можете ли вы создать ссылку на песочницу без проблем, с которыми вы столкнулись?
Что значит «без той проблемы, которая у вас есть»? Вот песочница, кстати, но с проблемой.
О, на самом деле компонент слайдера генерирует только событие ввода, поэтому изменение события не работает, а также, как только вы редактируете ввод, валидатор вызывается дважды, что приводит к проблеме.
cleanMinPrice() и cleanMaxPrice() вызываются при событии blur. Вы имеете в виду какие-то другие валидаторы? Я в замешательстве, потому что они находятся внутри пакета vuelidate, и у меня нет прямого доступа к функциям валидатора.
Вычисляемое свойство правил вызывается дважды при очистке значения, я думаю, что это может быть причиной проблемы.
Решением для меня стало использование компонента <InputNumber> PrimeVue. Он обновляет и проверяет значение в своем v-model по событию blur, а не по событию input. Это не означает, что для решения подобной проблемы следует использовать именно этот компонент, главное здесь то, что значение в v-model должно обновляться и проверяться, а не только проверяться, при размытии.
Примечание: в моем случае Vuelidate оказался излишним.
К сожалению, после того, как я изменил событие, появилась еще одна проблема. Я отредактирую пост и опишу его. И мне нужно событие, поскольку атрибуты
minValueиmaxValueведут себя не так, какv-model, как я вижу.