Vue 3 предоставляет расширенные возможности для работы с
v-model, включая возможность переименовывать
модельные свойства и события, что особенно полезно при создании
сложных компонентов с несколькими состояниями. Использование
Custom v-model позволяет компоненту быть
более гибким и интегрироваться с родительскими компонентами без жёсткой
привязки к стандартному modelValue.
v-modelПо умолчанию v-model в Vue 3 связывает внутреннее
состояние компонента с родительским через:
props: {
modelValue: String
},
emits: ['update:modelValue']
В шаблоне родителя это выглядит так:
<CustomInput v-model="text" />
Внутри компонента можно обновлять значение:
this.$emit('update:modelValue', newValue);
v-model через prop и eventVue 3 позволяет использовать несколько моделей одновременно, каждая с уникальным именем. Для этого в компоненте нужно явно указать имена пропсов и событий.
Пример:
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
В родительском компоненте это связывается так:
<CustomForm v-model:first-name="userFirstName" v-model:last-name="userLastName" />
Важно помнить, что событие должно строго соответствовать
шаблону update:имя_пропса.
v-model в компонентеМожно определить несколько v-model с разными именами в
одном компоненте:
<script setup>
import { ref, watch } from 'vue'
defineProps({
email: String,
password: String
})
defineEmits(['update:email', 'update:password'])
const internalEmail = ref(email)
const internalPassword = ref(password)
watch(internalEmail, value => {
emit('update:email', value)
})
watch(internalPassword, value => {
emit('update:password', value)
})
</script>
<template>
<input v-model="internalEmail" placeholder="Email" />
<input v-model="internalPassword" placeholder="Password" type="password" />
</template>
Такой подход позволяет компоненту самостоятельно контролировать локальное состояние, не ломая двустороннюю связь с родителем.
v-model при экспорте компонентаДля более компактного использования в родителях можно задать
кастомное имя v-model при экспорте:
<script>
export default {
name: 'CustomInput',
props: {
valueText: String
},
emits: ['update:valueText']
}
</script>
Теперь в родительском шаблоне:
<CustomInput v-model:value-text="userInput" />
Это важно для избежания конфликта с другими
v-model или стандартным
modelValue.
Когда компонент содержит несколько полей, каждое
можно связать с отдельным v-model:
<MultiFieldForm
v-model:first-name="firstName"
v-model:last-name="lastName"
v-model:email="email"
/>
Компонент при этом должен:
v-model.update:имя_пропса.Такой подход упрощает интеграцию сложных форм с внешними состояниями, сохраняя реактивность Vue.
update:
(v-model:prop-name → update:propName).v-model использовать
defineProps и defineEmits в
<script setup> или стандартные опции в Options
API.ref) позволяют
избежать непреднамеренного изменения внешнего состояния
до подтверждения изменений.emit, но это снижает
читаемость и предсказуемость кода.<script setup>
import { ref, watch } from 'vue'
defineProps({
username: String,
age: Number
})
defineEmits(['update:username', 'update:age'])
const internalUsername = ref(username)
const internalAge = ref(age)
watch(internalUsername, value => emit('update:username', value))
watch(internalAge, value => emit('update:age', value))
</script>
<template>
<input v-model="internalUsername" placeholder="Username" />
<input v-model="internalAge" placeholder="Age" type="number" />
</template>
Родительский компонент:
<UserForm v-model:username="user.name" v-model:age="user.age" />
Такой подход гарантирует чистую двустороннюю связь и удобное управление состоянием без конфликтов с другими компонентами.
Этот механизм Custom v-model делает компоненты Vue
гибкими, масштабируемыми и предсказуемыми, особенно при
создании сложных интерфейсов с множественными формами и полями.