Aprenda a trabalhar com inputs de formulário com uma aula gratuita da Vue School
Você pode usar a diretiva v-model
para criar interligações de dados de mão dupla (two-way data binding) em elementos input, textarea e select de formulários. Ela, automaticamente, escolhe a maneira correta de atualizar o elemento baseado no tipo do input. Embora um pouco mágica, v-model
é, essencialmente, uma forma simplificada (syntax sugar) para atualizar dados nos eventos de entrada do usuário, além de cuidado especial com casos extremos.
::: tip Nota
v-model
irá ignorar o estado inicial dos atributos value
, checked
ou selected
encontrado em qualquer elemento de formulário. Ela sempre irá tratar os dados da instância ativa como a fonte de informação (source of truth). Você pode declarar o valor inicial no lado do JavasScript, dentro da opção data
de seu componente.
:::
v-model
utiliza diferentes propriedades internamente e emite diferentes eventos para diferentes elementos input:
- elementos text e textarea usam a propriedade
value
e o eventoinput
; - checkboxes e radiobuttons utilizam a propriedade
checked
e o eventochange
; - campos de seleção utilizam
value
como propriedade echange
como um evento.
::: tip Nota
Você pode notar que v-model
não é atualizada durante a composição através de um editor de método de entrada (IME), como em Chinês, Japonês, Coreano, etc. Se você também quiser responder a essas atualizações, use diretamente um evento de input
e value
vinculado ao invés da v-model
.
:::
<input v-model="message" placeholder="Me edite" />
<p>A mensagem é: {{ message }}</p>
<span>Mensagem com múltiplas linhas:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br />
<textarea v-model="message" placeholder="Escreva bastante"></textarea>
Interpolação em textareas (<textarea>{{text}}</textarea>
) não funcionará. Em vez disso, use v-model
.
<!-- ruim -->
<textarea>{{ text }}</textarea>
<!-- bom -->
<textarea v-model="text"></textarea>
Caixa de seleção única, valor do tipo boolean:
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
Múltiplos checkboxes, associados ao mesmo array:
<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>Nomes selecionados: {{ checkedNames }}</span>
</div>
Vue.createApp({
data() {
return {
checkedNames: []
}
}
}).mount('#v-model-multiple-checkboxes')
<div id="v-model-radiobutton">
<input type="radio" id="one" value="Primeiro" v-model="picked" />
<label for="one">Um</label>
<br />
<input type="radio" id="two" value="Segundo" v-model="picked" />
<label for="two">Dois</label>
<br />
<span>Escolhido: {{ picked }}</span>
</div>
Vue.createApp({
data() {
return {
picked: ''
}
}
}).mount('#v-model-radiobutton')
Seleção de um único item:
<div id="v-model-select" class="demo">
<select v-model="selected">
<option disabled value="">Escolha um</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selecionado: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return {
selected: ''
}
}
}).mount('#v-model-select')
:::tip Nota
Se o valor inicial da expressão v-model
não corresponder a nenhuma das opções, o elemento <select>
será renderizado em um estado "não selecionado". No iOS, isso impedirá o usuário de selecionar o primeiro item, já que, neste caso, não há disparo do evento change
. Portanto, é recomendado fornecer uma opção desabilitada com um valor vazio, como demonstrado no exemplo acima.
:::
Seleção de múltiplos itens (vinculando a um array):
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br />
<span>Selecionado: {{ selected }}</span>
Renderização dinâmica de options com 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>Selecionado: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return {
selected: 'A',
options: [
{ text: 'Um', value: 'A' },
{ text: 'Dois', value: 'B' },
{ text: 'Três', value: 'C' }
]
}
}
}).mount('#v-model-select-dynamic')
Para radio, checkbox e select, a interligação de valores do v-model
são sempre strings estáticas (ou valores do tipo boolean, em checkboxes):
<!-- `picked` é uma string "a" quando assinalado -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` é verdadeiro ou falso -->
<input type="checkbox" v-model="toggle" />
<!-- `selected` é uma string "abc" quando a primeira opção for selecionada -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
Porém, às vezes, podemos querer vincular o valor a uma propriedade dinâmica na atual instância ativa. Nós podemos utilizar v-bind
para alcançar isso. Além disso, utilizando v-bind
nos permite vincular o valor de um input para valores que não são uma string (non-string values).
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
// quando assinalado:
vm.toggle === 'yes'
// quando não assinalado:
vm.toggle === 'no'
:::tip Dica
Os atributos true-value
e false-value
não afetam o atributo value
dos inputs, porque os browsers não incluem caixas de seleção não assinaladas nas submissões de formulários. Para garantir que um dos dois valores seja enviado em um formulário (p. ex. "sim" ou "não"), use inputs do tipo radio.
:::
<input type="radio" v-model="pick" v-bind:value="a" />
// quando assinalado:
vm.pick === vm.a
<select v-model="selected">
<!-- Objeto literal atribuído para demonstração -->
<option :value="{ number: 123 }">123</option>
</select>
// quando está assinalado:
typeof vm.selected // => 'object'
vm.selected.number // => 123
Por padrão, v-model
sincroniza o elemento input com os dados após cada evento input
(exceto para o caso de composição IME, como descrito anteriormente). Você pode adicionar o modificador lazy
para sincronizar depois do evento change
:
<!-- sincronizado depois do "change" ao invés de "input" -->
<input v-model.lazy="msg" />
Se você deseja que a entrada do usuário seja automaticamente tipificada como um Number, pode adicionar o modificador number
ao v-model
do elemento:
<input v-model.number="age" type="text" />
Isso geralmente é útil quando o tipo do input é text
. Se o tipo do input for number
, o Vue pode converter automaticamente o valor bruto da string para número, e você não precisa adicionar o modificador .number
ao v-model
. Se o valor não puder ser convertido com parseFloat()
, então o valor original é retornado.
Se você quiser que os espaços em branco excedentes de um input sejam automaticamente removidos, é possível adicionar o modificador trim
ao v-model
do elemento:
<input v-model.trim="msg" />
Se você ainda não está familiarizado com os componentes Vue, pode pular esta parte, por enquanto.
Os tipos de input nativos do HTML nem sempre atendem as suas necessidades. Felizmente, os componentes Vue te permitem construir inputs reutilizáveis com comportamento completamente customizável. Estes componentes também funcionam com v-model
! Para saber mais, leia sobre inputs customizados no guia de Componentes.