Vinculación de Entradas de Formularios
Cuando tratamos con formularios en el frontend, a menudo necesitamos sincronizar el estado de los elementos de entrada del formulario con el estado correspondiente en JavaScript. Puede ser incómodo configurar manualmente los enlaces de valores y cambiar los escuchadores de eventos:
template
<input
:value="text"
@input="event => text = event.target.value">
La directiva v-model
nos ayuda a simplificar lo anterior a:
template
<input v-model="text">
Además, v-model
se puede utilizar en entradas de diferentes tipos, <textarea>
, y elementos <select>
. Esto se propaga automáticamente a diferentes propiedades del DOM y pares de eventos basados en el elemento en el que se utiliza:
<input>
con tipos de texto y elementos<textarea>
utilizan la propiedadvalue
y el eventoinput
;<input type="checkbox">
al igual que<input type="radio">
utilizan la propiedadchecked
y el eventochange
;<select>
utiliza la propiedadvalue
ychange
como un evento.
Nota
v-model
ignorará los atributos iniciales value
, checked
o selected
encontrados en cualquier elemento del formulario. Este siempre tratará el estado del JavaScript enlazado actual como la fuente de la verdad. Debes declarar el valor inicial en el lado de JavaScript, utilizando las APIs de reactividad.
Uso Básico
Texto
template
<p>El mensaje es: {{ message }}</p>
<input v-model="message" placeholder="edítame" />
El mensaje es:
Nota
Para los lenguajes que requieren un IME (Chino, Japonés, Coreano, etc.), notarás que el v-model
no se actualiza durante la composición del IME. Si quieres responder también a estas actualizaciones, utiliza un receptor de eventos input
y un enlace value
en lugar de utilizar v-model
.
Texto Multilínea
template
<span>El mensaje multilínea es:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="agrega múltiples líneas"></textarea>
El mensaje multilínea es:
Observa que la interpolación dentro del <textarea>
no funcionará. En su lugar, utiliza v-model
.
template
<!-- erróneo -->
<textarea>{{ text }}</textarea>
<!-- correcto -->
<textarea v-model="text"></textarea>
Checkbox
Un único checkbox, con valor booleano:
template
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
También podemos vincular múltiples checkboxes al mismo array o valor Set:
js
const checkedNames = ref([])
template
<div>Nombres verificados: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
Nombres verificados: []
En este caso, el array checkedNames
siempre contendrá los valores de las casillas seleccionadas en ese momento.
Radio
template
<div>Seleccionado: {{ picked }}</div>
<input type="radio" id="one" value="Uno" v-model="picked" />
<label for="one">Uno</label>
<input type="radio" id="two" value="Dos" v-model="picked" />
<label for="two">Dos</label>
Seleccionado:
Select
Select Simple:
template
<div>Selección: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Por favor, selecciona uno</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
Selección:
Nota
Si el valor inicial de tu expresión v-model
no coincide con ninguna de las opciones, el elemento <select>
se mostrará en un estado "no seleccionado". En iOS esto hará que el usuario no pueda seleccionar el primer elemento porque iOS no dispara un evento de cambio en este caso. Por lo tanto, se recomienda proporcionar una opción deshabilitada con un valor vacío, como se demuestra en el ejemplo anterior.
Selección múltiple (vinculada a un array):
template
<div>Seleccionado: {{ selected }}</div>
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
Seleccionado: []
Las opciones de selección se pueden representar dinámicamente con v-for
:
js
const selected = ref('A')
const options = ref([
{ text: 'Uno', value: 'A' },
{ text: 'Dos', value: 'B' },
{ text: 'Tres', value: 'C' }
])
template
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<div>Seleccionado: {{ selected }}</div>
Vinculación de Valores
En las opciones radio, checkbox y select, los valores de enlace del v-model
suelen ser cadenas estáticas (o booleanas en el caso de los checkbox):
template
<!-- `picked` es una cadena "a" cuando se selecciona -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` puede ser verdadero o falso -->
<input type="checkbox" v-model="toggle" />
<!-- `selected` es una cadena "abc" cuando se selecciona la primera opción -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
Pero en ocasiones podemos querer vincular el valor a una propiedad dinámica de la instancia activa actual. Para ello podemos utilizar v-bind
. Además, el uso de v-bind
nos permite vincular el valor de entrada a valores que no son de cadena.
Checkbox
template
<input
type="checkbox"
v-model="toggle"
true-value="sí"
false-value="no" />
true-value
y false-value
son atributos específicos de Vue que sólo funcionan con v-model
. En este caso, el valor de la propiedad toggle
se establecerá en 'sí'
cuando la casilla esté marcada, y en 'no'
cuando esté desmarcada. También puedes vincularlos a valores dinámicos usando v-bind
:
template
<input
type="checkbox"
v-model="toggle"
:true-value="dynamicTrueValue"
:false-value="dynamicFalseValue" />
Tip
Los atributos true-value
y false-value
no afectan al atributo value
de la entrada, porque los navegadores no incluyen las casillas sin marcar en los envíos de formularios. Para garantizar que uno de los dos valores se envíe en un formulario (por ejemplo, "sí" o "no"), utiliza entradas de radio en su lugar.
Radio
template
<input type="radio" v-model="pick" :value="primero" />
<input type="radio" v-model="pick" :value="segundo" />
pick
se establecerá con el valor de primero
cuando se marque la primera entrada de radio, y se establecerá con el valor de segundo
cuando se marque la segunda.
Opciones de Select
template
<select v-model="selected">
<!-- objeto literal en línea -->
<option :value="{ number: 123 }">123</option>
</select>
v-model
admite también la vinculación de valores que no sean cadenas. En el ejemplo anterior, cuando se selecciona la opción, selected
se establecerá en el valor literal del objeto de { number: 123 }
.
Modificadores
.lazy
Por defecto, v-model
sincroniza la entrada con los datos después de cada evento input
(con la excepción de la composición IME, como se ha indicado anteriormente). Puedes añadir el modificador lazy
para sincronizar después de los eventos change
:
template
<!-- sincronizado después de "change" en lugar de "input" -->
<input v-model.lazy="msg" />
.number
Si quieres que la entrada del usuario sea automáticamente tipificada como un número, puedes añadir el modificador number
a tus entradas gestionadas por v-model
:
template
<input v-model.number="age" />
Si el valor no puede ser procesado con parseFloat()
, entonces se utiliza el valor original.
El modificador number
se aplica automáticamente si la entrada tiene type="number"
.
.trim
Si quieres que los espacios en blanco de la entrada del usuario se recorten automáticamente, puedes añadir el modificador trim
a tus entradas gestionadas por v-model
:
template
<input v-model.trim="msg" />
v-model
con Componentes
Si aún no estás familiarizado con los componentes de Vue, puedes saltarte esto por ahora.
Los tipos de entrada incorporados en HTML no siempre satisfacen tus necesidades. Afortunadamente, los componentes de Vue te permiten construir entradas reutilizables con un comportamiento completamente personalizado. ¡Estas entradas incluso funcionan con v-model
! Para aprender más, lee sobre Uso con v-model
en la guía de Componentes.