Как передать модификаторы v-model в кастомный компонент для ввода?

Родительский компонент использует стилизованный компонент инпута и передаёт ему v-model, который может включать разные модификаторы (lazy, number, trim). 

В кастомном инпуте мне нужно передать аналогичный v-model (с теми же модификаторами) во внутренний инпут. 

<b>Как это можно реализовать?</b> 

По сути, задача заключается в том, чтобы динамически сформировать что-то вроде <code class="javascript">&lt;input v-model[.lazy][.trim][.number]=" ...</code>. 

Пока что я смог извлечь <code class="javascript">modelModifiers</code> следующим образом: 
<code class="javascript">const [modelValue, modelModifiers] = defineModel()</code>. 

<a href="https://vuejs.org/api/sfc-script-setup.html#modifiers-and-transformers" rel="nofollow">Вот ссылка на пример из документации</a>, где рассматривается схожая ситуация, но там модификаторы обрабатываются вручную. Мне же хотелось бы передать их напрямую, без необходимости создавать собственные обработки модификаторов.
  • 2 ноября 2024 г. 15:42
Ответы на вопрос 3
Чтобы передать модификаторы `v-model` из родительского компонента в кастомный компонент без необходимости вручную обрабатывать их, вы можете использовать слоты или пропс для передачи значений, в зависимости от конкретной реализации. Одна из наиболее распространенных практик — это использовать `v-bind` для передачи модификаторов в ваш внутренний `<input>`. 

Вот пример, как можно это реализовать:

1. В вашем кастомном компоненте (`CustomInput.vue`), воспользуйтесь `defineModel()` для извлечения `modelValue` и `modelModifiers`, как вы уже сделали.

2. Затем вы можете использовать эти значения с помощью директивы `v-bind` на внутреннем `<input>`.

Пример кода:

```vue
<template>
  <input
    v-bind="inputBindings"
    :value="modelValue"
    @input="onInput"
  />
</template>

<script setup>
import { defineModel } from 'vue'

const { modelValue, modelModifiers } = defineModel()

// Подготовим объект с необходимыми атрибутами для <input>
const inputBindings = {
  lazy: modelModifiers.lazy,
  trim: modelModifiers.trim,
  number: modelModifiers.number,
};

// Обработчик события input
function onInput(event) {
  // Обновляем значение с учетом модификаторов
  let newValue = event.target.value;

  if (modelModifiers.trim) {
    newValue = newValue.trim();
  }
  if (modelModifiers.number) {
    newValue = Number(newValue);
  }
  
  emit('update:modelValue', newValue);
}
</script>
```

### Пояснения:
- `v-bind="inputBindings"` позволяет динамически добавить атрибуты в ваш `<input>` элемент.
- В `onInput` обработчике мы учли модификаторы `trim` и `number`, чтобы обработать вводимое значение в соответствии с ними и обновить `modelValue`.

### Использование компонента
Теперь вы можете использовать ваш кастомный компонент в родительском компоненте следующим образом:

```vue
<template>
  <CustomInput v-model.lazy="inputValue" />
</template>

<script setup>
import { ref } from 'vue'

const inputValue = ref('');
</script>
```

Таким образом, модификаторы `lazy`, `trim` и `number` будут автоматически передаваться во внутренний `<input>` вашего кастомного компонента, что избавит вас от необходимости писать обработчики для каждого модификатора.
Нашёл ещё функцию withModifiers, но она только для v-on событий

А какая разница? Это же будет внутри компонента, а снаружи v-model останется как был. Почему бы не попробовать завернуть в этот withModifiers установку нового значения? Единственное, что придётся в явном виде обрабатывать, это модификатор lazy - чтобы правильные события слушать. Как-то так :

const [ model, modifiers ] = defineModel();

const event = modifiers.lazy ? 'change' : 'input';
const handler = withModifiers(
  e => model.value = e.target.value,
  Object.keys(modifiers)
);

<input :value="model" @[event]="handler">
Использовать вместо v-model отдельно :model-value :model-modifiers и событие @update:model-value не работает?
Похожие вопросы