Aprender cómo manejar entradas de formularios con una lección gratis en Vue School
Puede utilizar la directiva v-model
para crear vinculaciones de datos de doble direcciones (two-way data binding) en elementos input, textarea y select de un formulario. La directiva busca automáticamente la manera correcta de actualizar el elemento según el tipo de entrada. Aunque un poco mágico, v-model
es esencialmente azúcar de sintaxis para actualización de datos a través de eventos de entradas del usuario, además de mostrar un cuidado especial para algunos casos de borde.
::: tip Note
v-model ignorará los atributos iniciales de value
, checked
o selected
encontrados en cualquier elemento de formulario, Siempre tratará los datos de la actual instancia activa como la fuente de verdad. Debería declarar el valor inicial del lado de JavaScript, dentro de la opción data
de su componente.
:::
v-model
internamente utiliza propiedades distintas y emitir eventos distintos para distintos elementos de entrada:
- Los elementos de texto y textarea utilizan propiedad
value
y eventoinput
; - checkbox y radio utilizan propiedad
checked
y eventochange
; - Los campos de select utilizan propiedad
value
y eventochange
.
::: tip Note
Para los idiomas que requieren un IME (chino, japonés, coreano, etc.), notará que el v-model
no se actualiza durante la composición del IME. Si también desea responder a estas actualizaciones, utilice un escuchador de evento input
y la vinculación de value
en vez de utilizar v-model
.
:::
<input v-model="message" placeholder="edit me" />
<p>El mensaje es: {{ message }}</p>
<span>El mensaje multilínea es:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br />
<textarea v-model="message" placeholder="introducir múltiples líneas"></textarea>
Interpolación sobre textarea no funcionará. Utilice v-model
en su lugar.
<!-- mal -->
<textarea>{{ text }}</textarea>
<!-- bien -->
<textarea v-model="text"></textarea>
Un solo checkbox con valor booleano:
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
Múltiples checkbox, vinculados a la misma matriz:
<div id="v-model-multiple-checkboxes">
<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>
<br />
<span>Nombres marcados: {{ checkedNames }}</span>
</div>
Vue.createApp({
data() {
return {
checkedNames: []
}
}
}).mount('#v-model-multiple-checkboxes')
<div id="v-model-radiobutton">
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<br />
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<br />
<span>Picked: {{ picked }}</span>
</div>
Vue.createApp({
data() {
return {
picked: ''
}
}
}).mount('#v-model-radiobutton')
Un solo select:
<div id="v-model-select" class="demo">
<select v-model="selected">
<option disabled value="">Seleccione una opción por favor:</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Seleccionado: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return {
selected: ''
}
}
}).mount('#v-model-select')
:::tip Note
Si el valor inicial de su expresión v-model
no coincide con ninguna de las opciones, el elemento <select>
se renderizará 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 muestra en el ejemplo anterior.
:::
Selección de múltiples elementos (vinculados a una matriz):
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br />
<span>Seleccionado: {{ selected }}</span>
Opciones dinámicas renderizadas con v-for
:
<div id="v-model-select-dynamic" class="demo">
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<span>Seleccionado: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return {
selected: 'A',
options: [
{ text: 'Uno', value: 'A' },
{ text: 'Dos', value: 'B' },
{ text: 'Tres', value: 'C' }
]
}
}
}).mount('#v-model-select-dynamic')
Para opciones de radio, checkbox y select, los valores vinculados de v-model
son usualmente cadenas de caracteres estáticas (o booleanos para checkbox):
<!-- `picked` es una cadena de caracteres "a" cuando está chequeado -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` es o `true` o `false` -->
<input type="checkbox" v-model="toggle" />
<!-- `selected` es una cadena de caracteres "abc" cuando se selecciona la primera opción -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
Pero a veces es posible que queramos vincular el valor a una propiedad dinámica en la actual instancia activa. Podemos utilizar v-bind
para lograrlo. Además, el uso de v-bind
nos permite vincular el valor de entrada a valores que no son cadenas de caracteres.
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
// cuando está marcado:
vm.toggle === 'yes'
// cuando está desmarcado:
vm.toggle === 'no'
:::tip Tip
Los atributos de true-value
y de false-value
no afectan el atributo value
del la entrada, ya que los navegadores no incluyen checkbox desmarcados en los envíos de formularios. Para garantizar que uno de los dos valores se envie en un formulario (por ejemplo, “yes” o “no”), use entradas de radio en su lugar.
:::
<input type="radio" v-model="pick" v-bind:value="a" />
// cuando está marcado:
vm.pick === vm.a
<select v-model="selected">
<!-- objeto literal en línea -->
<option :value="{ number: 123 }">123</option>
</select>
// cuando está seleccionado:
typeof vm.selected // => 'object'
vm.selected.number // => 123
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 descrito anteriormente). En lugar de esto, puede agregar el modificador lazy
para realizar la sincronización después del evento change
:
<!-- sincronizado después de "change" en lugar de "input" -->
<input v-model.lazy="msg" />
Si desea que la entrada del usuario se convierten automáticamente en un número, puede agregar el modificador number
al v-model
de la entrada manejada:
<input v-model.number="age" type="text" />
Esto suele ser útil cuando el tipo de la entrada es text
. Si el tipo es number
, Vue puede automáticamente convertir el valor de la cadena de caracteres original a un número, así no necesita agregar el modificador .number
al v-model
. Si el valor no se puede analizar con parseFloat()
, se retorna el valor original.
Si desea que las entradas del usuario se recorten automáticamente, puede agregar el modificador trim
al v-model
de la entrada manejada:
<input v-model.trim="msg" />
Si aún no está familiarizado con los componentes de Vue, puede omitir esto por ahora.
Los tipos de entradas nativas de HTML no siempre satisfarán sus necesidades. Afortunadamente, los componentes de Vue le permiten crear entradas reutilizables con un comportamiento completamente personalizado. ¡Estos componentes también funcionan con v-model
! Para aprender más, lea acerca de entradas personalizadas en la guía de componentes.