Небольшая ошибка ползунка цены при первом вводе другого значения

У меня есть ползунок цен и два входа для минимальной и максимальной цены. У меня есть небольшой баг. Когда я пытаюсь ввести другое значение в поле минимальной цены и начинаю стирать предыдущее, оно сразу меняется на 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:&nbsp;&nbsp;</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:&nbsp;&nbsp;</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"
/>
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете просто изменить событие input на keyDown или change. Также я думаю, что вам не нужны какие-либо события, поскольку вы используете наблюдатели, поэтому ваши значения будут автоматически обновляться при минимальном и максимальном изменении.

К сожалению, после того, как я изменил событие, появилась еще одна проблема. Я отредактирую пост и опишу его. И мне нужно событие, поскольку атрибуты minValue и maxValue ведут себя не так, как v-model, как я вижу.

Angelina 13.06.2024 11:29

Я попробовал ваш код, и он работает нормально в обоих случаях. Можете ли вы создать ссылку на песочницу без проблем, с которыми вы столкнулись?

Yash Maheshwari 13.06.2024 11:33

Что значит «без той проблемы, которая у вас есть»? Вот песочница, кстати, но с проблемой.

Angelina 13.06.2024 12:23

О, на самом деле компонент слайдера генерирует только событие ввода, поэтому изменение события не работает, а также, как только вы редактируете ввод, валидатор вызывается дважды, что приводит к проблеме.

Yash Maheshwari 13.06.2024 12:47
cleanMinPrice() и cleanMaxPrice() вызываются при событии blur. Вы имеете в виду какие-то другие валидаторы? Я в замешательстве, потому что они находятся внутри пакета vuelidate, и у меня нет прямого доступа к функциям валидатора.
Angelina 13.06.2024 13:12

Вычисляемое свойство правил вызывается дважды при очистке значения, я думаю, что это может быть причиной проблемы.

Yash Maheshwari 13.06.2024 13:28
Ответ принят как подходящий

Решением для меня стало использование компонента <InputNumber> PrimeVue. Он обновляет и проверяет значение в своем v-model по событию blur, а не по событию input. Это не означает, что для решения подобной проблемы следует использовать именно этот компонент, главное здесь то, что значение в v-model должно обновляться и проверяться, а не только проверяться, при размытии.

Примечание: в моем случае Vuelidate оказался излишним.

Вот песочница с решенной проблемой.

Другие вопросы по теме