Skip to content
← Todas las preguntas
Intermedio

¿Cómo funcionan los bindings múltiples de v-model en un componente?

ComponentesDirectivas

Desde Vue 3, puedes enlazar múltiples directivas v-model a un solo componente dándole un nombre a cada una. Esto reemplaza el patrón de Vue 2 de un v-model más modificadores .sync.

Uso básico

vue
<!-- Parent.vue -->
<template>
  <UserForm v-model:first-name="first" v-model:last-name="last" />
</template>

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

const first = ref('Ana')
const last = ref('García')
</script>
vue
<!-- UserForm.vue -->
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>

<template>
  <input v-model="firstName" placeholder="Nombre" />
  <input v-model="lastName" placeholder="Apellido" />
</template>

defineModel (Vue 3.4+) crea un binding bidireccional automáticamente. Cada modelo con nombre corresponde a un v-model:nombre en el padre.

Cómo funciona bajo el capó

v-model:firstName="first" es una abreviatura de:

vue
<UserForm
  :firstName="first"
  @update:firstName="first = $event"
/>

Y defineModel('firstName') es una abreviatura de:

vue
<script setup>
const props = defineProps<{ firstName: string }>()
const emit = defineEmits<{ 'update:firstName': [value: string] }>()

// Un computed con escritura que actúa como proxy de la prop
const firstName = computed({
  get: () => props.firstName,
  set: (val) => emit('update:firstName', val)
})
</script>

v-model por defecto (sin nombre) junto con los nombrados

El v-model por defecto (sin nombre) usa modelValue como nombre de prop:

vue
<!-- Parent.vue -->
<template>
  <SearchInput v-model="query" v-model:filters="activeFilters" />
</template>
vue
<!-- SearchInput.vue -->
<script setup>
const query = defineModel()              // corresponde a v-model (modelValue)
const filters = defineModel('filters')   // corresponde a v-model:filters
</script>

Añadir tipos

vue
<script setup lang="ts">
const firstName = defineModel<string>('firstName', { required: true })
const age = defineModel<number>('age', { default: 0 })
</script>

Antes de defineModel (Vue < 3.4)

Si estás en una versión antigua de Vue 3, declaras las props y emits manualmente:

vue
<script setup>
const props = defineProps<{
  firstName: string
  lastName: string
}>()

const emit = defineEmits<{
  'update:firstName': [value: string]
  'update:lastName': [value: string]
}>()
</script>

<template>
  <input
    :value="firstName"
    @input="emit('update:firstName', ($event.target as HTMLInputElement).value)"
  />
  <input
    :value="lastName"
    @input="emit('update:lastName', ($event.target as HTMLInputElement).value)"
  />
</template>

defineModel elimina todo este boilerplate.

Cuándo usar múltiples v-model

EscenarioEnfoque
Un solo valor (input de búsqueda, toggle)v-model (sin nombre)
Formulario con varios campos relacionadosMúltiples v-model con nombre
Objeto complejo como valor únicov-model único con un tipo de objeto
Valores no relacionados que cambian de forma independienteMúltiples v-model con nombre

Publicado bajo la licencia MIT.