хук useInput.
Задача: внутри хука useInput менять значение вводимых символов и оставлять только цифры, а потом возвращать новое значение inputValue в компонент и обновлять modelValue на inputValue.
Проблема: есть рассинхронизация между modelValue у инпута и отображаемыми значениями. То есть у modelValue всё корректно отображается, а на экране неправильно. Например, если вводить буквы, то modelValue не будет обновляться, но буквы будут появляться на экране. Причем если вместо букв ввести цифру, то значения modelValue и инпута на экране синхронизируются.
Вопрос: из-за чего может быть такое поведение?
Интересный факт: если внутри хука в регулярном выражении менять символы не на пустую строку, а на пробел, например, то всё нормально будет работать 🙄
Код компонента: <script setup lang="ts"> import useInput from '~/composables/input'; /** Пропсы компонента */ interface Props { /** ID поля */ id: string; /** Имя поля */ name: string; /** Значение поля */ modelValue: string; /** Тип поля */ type?: string; /** Замещающий текст */ placeholder?: string; /** Тип автозаполнения */ autocomplete?: string; /** Разрешенные символы */ pattern?: string; /** Обязательно ли заполнять поле */ isRequired?: boolean; } /** Пропсы */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const props = defineProps<Props>(); // eslint-disable-next-line @typescript-eslint/no-unused-vars const emits = defineEmits(['update:modelValue']); /** Переключить интенсивность цвета у заполнителя поля телефона */ const togglePhonePlaceholderIntense = (event: Event) => { const target = event.target as HTMLInputElement; if (target.type === 'tel') { target.classList.toggle('input--intense-placeholder'); } }; /** Обработать ввод */ const handleInput = (event: Event) => { const { inputValue } = useInput(event.target as HTMLInputElement); emits('update:modelValue', inputValue.value); }; </script> <template> <input :id="id" :name="name" :value="modelValue" :type="type" :placeholder="placeholder" :autocomplete="autocomplete" :pattern="pattern" :required="isRequired" class="input" @input="handleInput" @focusin="togglePhonePlaceholderIntense" @focusout="togglePhonePlaceholderIntense" /> </template> Код хука: import { ref } from 'vue'; /** Хук для управления полем ввода */ export default function useInput(target: HTMLInputElement) { const inputValue = ref(''); const handleTelInput = () => { inputValue.value = target.value.replace(/\D/g, ''); }; if (target.type === 'tel') { handleTelInput(); } return { inputValue, }; }
начнем с того, что у тебя структура вообще неверная: твой композабл на самом деле не композабл, это просто обычная функция, которую ты вызываешь в обработчике и на каждое изменение создаешь новый реф, так не нужно делать композабл должен вызываться 1 раз в корне сетапа, а не в обработчиках
Насчёт структуры понял, спасибо) Наверное, лучше вообще удалить этот композабл и писать логику сразу в компоненте?
пока выглядит так, что да, он особо и не нужен, т.к. даже реф оттуда не переиспользуется лучше пока вынести все это в компонент, а потом уже смотреть, понадобится ли тебе в разных компонентах одна и та же логика
Согласен, сейчас попробую)
В общем разобрался: я в обработчике обновлял стороннюю реактивную переменную, а не target.value) А надо было так: const handleInput = (event: Event) => { const target = event.target as HTMLInputElement; if (target.type === 'tel') { target.value = target.value.replace(/\D/g, ''); } emits('update:modelValue', target.value); }; Но пока не перенес логику из хука в компонент, не мог понять этого 😅 Спасибо за помощь))
Обсуждают сегодня