→ Vue.js para iniciantes lição 1: instância Vue
→ Vue.js para iniciantes, lição 2: atributos de vinculação
→ Vue.js para iniciantes lição 3: renderização condicional
→ Vue.js para iniciantes lição 4: exibição de listas
→ Vue .js para iniciantes lição 5: processamento de eventos
→ Vue.js para iniciantes lição 6: ligando classes e estilos
→ Vue.js para iniciantes lição 7: propriedades calculadas
→ Vue.js para iniciantes lição 8: componentes
→ Vue. js para iniciantes lição 9: eventos personalizados
O propósito da lição
Vamos criar um formulário que permite aos visitantes do site enviar análises de produtos. Nesse caso, é necessário que o envio da resenha só seja possível se todos os campos do formulário estiverem preenchidos, os quais devem ser preenchidos.
Código inicial
Aqui está o que está acontecendo agora
index.html:
<div id="app">
<div class="cart">
<p>Cart({{ cart.length }})</p>
</div>
<product :premium="premium" @add-to-cart="updateCart"></product>
</div>
É assim
main.js:
Vue.component('product', {
props: {
premium: {
type: Boolean,
required: true
}
},
template: `
<div class="product">
<div class="product-image">
<img :src="image" />
</div>
<div class="product-info">
<h1>{{ title }}</h1>
<p v-if="inStock">In stock</p>
<p v-else>Out of Stock</p>
<p>Shipping: {{ shipping }}</p>
<ul>
<li v-for="detail in details">{{ detail }}</li>
</ul>
<div
class="color-box"
v-for="(variant, index) in variants"
:key="variant.variantId"
:style="{ backgroundColor: variant.variantColor }"
@mouseover="updateProduct(index)"
></div>
<button
v-on:click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"
>
Add to cart
</button>
</div>
</div>
`,
data() {
return {
product: 'Socks',
brand: 'Vue Mastery',
selectedVariant: 0,
details: ['80% cotton', '20% polyester', 'Gender-neutral'],
variants: [
{
variantId: 2234,
variantColor: 'green',
variantImage: './assets/vmSocks-green.jpg',
variantQuantity: 10
},
{
variantId: 2235,
variantColor: 'blue',
variantImage: './assets/vmSocks-blue.jpg',
variantQuantity: 0
}
]
}
},
methods: {
addToCart() {
this.$emit('add-to-cart', this.variants[this.selectedVariant].variantId);
},
updateProduct(index) {
this.selectedVariant = index;
console.log(index);
}
},
computed: {
title() {
return this.brand + ' ' + this.product;
},
image() {
return this.variants[this.selectedVariant].variantImage;
},
inStock() {
return this.variants[this.selectedVariant].variantQuantity;
},
shipping() {
if (this.premium) {
return "Free";
} else {
return 2.99
}
}
}
})
var app = new Vue({
el: '#app',
data: {
premium: true,
cart: []
},
methods: {
updateCart(id) {
this.cart.push(id);
}
}
})
Tarefa
Precisamos que os visitantes do site possam deixar comentários sobre os produtos, mas nosso site ainda não possui meios para receber dados dos usuários. As formas são esses meios.
A solução do problema
Para resolver a tarefa diante de nós, precisamos criar um formulário. Vamos começar criando um novo componente especificamente para trabalhar com um formulário. Vamos chamar esse componente
product-review. Este nome foi escolhido porque o componente proporcionará o funcionamento do formulário destinado à coleta de avaliações de produtos. O componente product-reviewserá aninhado dentro do componente product.
Vamos registrar um novo componente, começar a formar seu template e equipá-lo com alguns dados:
Vue.component('product-review', {
template: `
<input>
`,
data() {
return {
name: null
}
}
})
Como você pode ver, há um elemento no modelo do componente
<input>e uma propriedade nos dados do componente data, embora esteja vazio.
Como vinculo o que o usuário insere em um campo a uma propriedade
name?
Nas lições anteriores, falamos sobre vinculação de dados usando diretivas
v-bind, mas consideramos apenas a vinculação unilateral. O fluxo de dados foi da propriedade que armazena os dados para o controle que os renderiza. E agora precisamos que o que o usuário insere no campo seja na propriedade namearmazenada nos dados do componente. Em outras palavras, queremos que o fluxo de dados seja direcionado do campo de entrada para a propriedade.
Diretiva modelo V
A diretiva
v-modelpermite organizar a vinculação de dados bidirecional. Com este esquema de trabalho, se algo novo aparecer no campo de entrada, isso leva a uma mudança nos dados. E, portanto, quando os dados são alterados, o estado do controle que usa esses dados é atualizado.
Vamos adicionar uma diretiva ao campo de entrada
v-modele vincular esse campo a uma propriedade namedos dados do componente.
<input v-model="name">
Agora vamos adicionar o código completo do formulário ao modelo do componente:
<form class="review-form" @submit.prevent="onSubmit">
<p>
<label for="name">Name:</label>
<input id="name" v-model="name" placeholder="name">
</p>
<p>
<label for="review">Review:</label>
<textarea id="review" v-model="review"></textarea>
</p>
<p>
<label for="rating">Rating:</label>
<select id="rating" v-model.number="rating">
<option>5</option>
<option>4</option>
<option>3</option>
<option>2</option>
<option>1</option>
</select>
</p>
<p>
<input type="submit" value="Submit">
</p>
</form>
Como você pode ver, os
v-modelcampos input, textareae estão equipados com a diretiva select. Observe que ao configurar o campo select, um modificador foi usado .number(falaremos sobre isso em mais detalhes abaixo). Isso permite que você converta os dados correspondentes em um tipo Number, embora geralmente sejam representados em uma string.
Vamos suplementar o conjunto de dados do componente adicionando a ele os dados aos quais os controles descritos acima estão vinculados:
data() {
return {
name: null,
review: null,
rating: null
}
}
Na parte superior do modelo de formulário, você pode ver que, quando o formulário é enviado, um método é chamado
onSubmit. Estaremos criando este método em breve. Mas primeiro, vamos falar sobre o papel da construção .prevent.
Este é um modificador de evento. Impede que a página seja recarregada após a ocorrência de um evento
submit. Existem também outros modificadores de eventos úteis . É verdade, não vamos falar sobre eles.
Agora estamos prontos para criar um método
onSubmit. Vamos começar com este código:
onSubmit() {
let productReview = {
name: this.name,
review: this.review,
rating: this.rating
}
this.name = null
this.review = null
this.rating = null
}
Como você pode ver, este método cria um objeto com base nos dados inseridos pelo usuário. Uma referência a ele é gravada em uma variável
productReview. Aqui nós cair em nullvalores de propriedade name, review, rating. Mas o trabalho ainda não acabou. Ainda precisamos enviar para algum lugar productReview. Para onde enviar este objeto?
Faz sentido armazenar análises de produtos no mesmo local onde os dados dos componentes são armazenados
product. Dado que o componente está product-reviewaninhado dentro do componente product, podemos dizer que ele product-reviewé filho do componente product. Como aprendemos na lição anterior, você pode usar eventos gerados para enviar dados de componentes filhos para componentes pais $emit.
Vamos refinar o método
onSubmit:
onSubmit() {
let productReview = {
name: this.name,
review: this.review,
rating: this.rating
}
this.$emit('review-submitted', productReview)
this.name = null
this.review = null
this.rating = null
}
Agora geramos um evento com um nome
review-submittede passamos o objeto recém-criado nele productReview.
Em seguida, precisamos organizar a escuta para este evento, colocando o
productseguinte no modelo :
<product-review @review-submitted="addReview"></product-review>
Esta linha é lida assim: "Quando ocorre um evento
review-submitted, o método do addReviewcomponente precisa ser executado product."
Aqui está o código para este método:
addReview(productReview) {
this.reviews.push(productReview)
}
Esse método pega o objeto
productReviewque veio do método onSubmite o coloca em uma matriz reviewsarmazenada nos dados do componente product. Mas ainda não existe tal array nos dados deste componente. Então, vamos adicioná-lo lá:
reviews: []
Maravilhoso! Os elementos do formulário agora estão vinculados aos dados do componente
product-review. Esses dados são usados para criar o objeto productReview. E esse objeto é passado, quando o formulário é enviado, para o componente product. Como resultado, o objeto é productReviewadicionado ao array reviews, que é armazenado nos dados do componente product.
Exibindo análises de produtos
Agora, resta exibir na página do produto as avaliações feitas pelos visitantes do site. Faremos isso no componente
product, colocando o código correspondente acima do código com o qual o componente product-reviewé colocado no componente product.
<div>
<h2>Reviews</h2>
<p v-if="!reviews.length">There are no reviews yet.</p>
<ul>
<li v-for="review in reviews">
<p>{{ review.name }}</p>
<p>Rating: {{ review.rating }}</p>
<p>{{ review.review }}</p>
</li>
</ul>
</div>
Aqui, criamos uma lista de revisões usando a diretiva
v-fore exibimos os dados armazenados no objeto reviewusando a notação de ponto.
Na tag,
<p>verificamos se há algo no array reviews(verificando seu comprimento). Se não houver nada no array, imprimimos uma mensagem There are no reviews yet.

Página de formulário de feedback
Validação de formulário
Os formulários geralmente contêm campos que devem ser preenchidos antes do envio do formulário. Por exemplo, não queremos que os usuários enviem resenhas em que o campo de texto da resenha esteja vazio.
Felizmente para nós, o HTML5 suporta o
required. Seu uso é parecido com este:
<input required >
Tal construção levará a uma exibição automática de uma mensagem de erro se o usuário tentar enviar um formulário no qual o campo obrigatório está vazio.

Mensagem de erro
Ter validadores de campo de formulário padrão no navegador é muito bom, pois pode nos livrar de criar nossos próprios validadores de campo. Mas a forma como a verificação de dados padrão é realizada pode, em alguns casos especiais, não nos servir. Nessa situação, faz sentido escrever seu próprio código de validação de formulário.
Validação de formulário personalizado
Vamos falar sobre como criar seu próprio sistema de validação de formulário.
Vamos incluir uma
product-reviewmatriz para armazenar mensagens de erro nos dados do componente . Vamos chamá-lo errors:
data() {
return {
name: null,
review: null,
rating: null,
errors: []
}
}
Gostaríamos de adicionar a este array informações sobre erros que ocorrem em situações onde os campos do formulário estão vazios. Estamos falando sobre o seguinte código:
if(!this.name) this.errors.push("Name required.")
if(!this.review) this.errors.push("Review required.")
if(!this.rating) this.errors.push("Rating required.")
A primeira dessas linhas diz ao sistema
namepara colocar errorsuma mensagem de erro no array se o campo estiver vazio Name required. Outras strings que validam os campos reviewe funcionam de maneira semelhante rating. Se algum deles estiver vazio, arrayuma mensagem de erro será enviada ao array .
Onde colocar esse código?
Desde que nós queremos as mensagens de erro a serem gravados para a matriz somente quando, ao tentar enviar o formulário, verifica-se que os campos são
name, reviewou estão submitpreenchido, podemos colocar esse código no método onSubmit. Além disso, iremos reescrever o código que já está nele, adicionando algumas verificações a ele:
onSubmit() {
if(this.name && this.review && this.rating) {
let productReview = {
name: this.name,
review: this.review,
rating: this.rating
}
this.$emit('review-submitted', productReview)
this.name = null
this.review = null
this.rating = null
} else {
if(!this.name) this.errors.push("Name required.")
if(!this.review) this.errors.push("Review required.")
if(!this.rating) this.errors.push("Rating required.")
}
}
Agora vamos verificar os campos
name, reviewe rating. Se houver dados em todos esses campos, criamos um objeto com base neles productReviewe o enviamos para o componente pai. Em seguida, as propriedades correspondentes são redefinidas.
Se pelo menos um dos campos estiver vazio, colocamos
errorsuma mensagem de erro no array , dependendo do que o usuário não inseriu antes de enviar o formulário.
Resta exibir esses erros, o que pode ser feito com o seguinte código:
<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</p>
Aqui, uma diretiva é usada
v-ifcom a qual verificamos o array errorsquanto à presença de mensagens de erro nele (na verdade, analisamos o comprimento do array). Se houver algo na matriz, é exibido um elemento <p>que, quando aplicado v-for, exibe uma lista de erros da matriz errors.

Mensagens de erro
Agora temos nosso próprio sistema de validação de formulário.
Usando o modificador .number
O modificador
.numberusado na diretiva v-modelpode ser muito útil. Mas, ao usá-lo, lembre-se de que há um problema com ele. Se o valor correspondente estiver vazio, ele será representado como uma string, não um número. O Livro de Receitas Vue oferece uma solução para este problema. Consiste em converter explicitamente o valor correspondente em um tipo numérico:
Number(this.myNumber)
Oficina
Adicione a seguinte pergunta ao formulário: "Você recomendaria este produto?" Faça com que o usuário possa responder usando os botões de opção sim e não. Verifique a resposta a esta pergunta e inclua os dados relevantes no objeto
productReview.
- Aqui está um modelo que você pode usar para resolver esse problema.
- Aqui está a solução para o problema.
Resultado
Hoje falamos sobre como trabalhar com formulários. Aqui está a coisa mais importante que você aprendeu hoje:
- Você pode usar a diretiva para organizar a vinculação de dados bidirecional para os elementos do formulário
v-model. - O modificador
.numberdiz a Vue para converter o valor correspondente em um tipo numérico. Mas ao trabalhar com isso, há um problema relacionado ao fato de que os valores vazios permanecem strings. - O modificador de evento
.preventpermite evitar que a página seja recarregada após o envio do formulário. - Com o Vue, você pode implementar um mecanismo bastante simples para validação de formulário personalizado.
Você fez sua lição de casa hoje?
→ Vue.js para iniciantes lição 1: instância Vue
→ Vue.js para iniciantes, lição 2: atributos de vinculação
→ Vue.js para iniciantes lição 3: renderização condicional
→ Vue.js para iniciantes lição 4: exibição de listas
→ Vue .js para iniciantes lição 5: processamento de eventos
→ Vue.js para iniciantes lição 6: ligando classes e estilos
→ Vue.js para iniciantes lição 7: propriedades calculadas
→ Vue.js para iniciantes lição 8: componentes
→ Vue. js para iniciantes lição 9: eventos personalizados
