→ 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
Queremos que o componente
productseja capaz de dizer à entidade pai, a instância raiz do Vue, que ocorreu um evento. Nesse caso, productdeve enviar, juntamente com a notificação da ocorrência do evento, alguns dados.
Código inicial
O arquivo de
index.htmlprojeto de amostra agora contém o seguinte código:
<div id="app">
<product :premium="premium"></product>
</div>
Aqui está o conteúdo do arquivo
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 class="cart">
<p>Cart({{ cart }})</p>
</div>
</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
}
],
cart: 0,
}
},
methods: {
addToCart() {
this.cart += 1;
},
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
}
})
Tarefa
Agora, quando
productapresentado como um componente independente, não productfaz sentido que o código relacionado ao carrinho de compras esteja nele. Se cada produto tiver sua própria cesta da qual precisamos monitorar o status, nosso aplicativo se tornará uma grande bagunça. Em vez disso, gostaríamos que o carrinho existisse na raiz da instância Vue. Também precisamos do componente para productinformar a instância raiz do Vue sobre a adição de itens ao carrinho, ou seja, sobre os cliques no botão Add to cart.
Decisão
Vamos mover os dados relacionados ao carrinho de volta para a instância raiz do Vue:
var app = new Vue({
el: '#app',
data: {
premium: true,
cart: 0
}
})
A seguir, vamos mover o modelo de carrinho de volta para
index.html, trazendo seu código para este formulário:
<div id="app">
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
<product :premium="premium"></product>
</div>
Agora, se você abrir a página do aplicativo em um navegador e clicar no botão
Add to cart, nada acontecerá conforme o esperado.

Clicar no botão Adicionar ao carrinho ainda não leva a nada
. O que deve acontecer quando este botão for clicado? Precisamos que, ao clicar nele, a instância raiz do Vue receba uma notificação, que chamaria um método que atualiza o carrinho, ou seja, atualiza o valor que está armazenado em
cart.
Para conseguir isso, vamos primeiro reescrever o código do método do
addToCartcomponenteproduct.
Agora é assim:
addToCart() {
this.cart += 1;
},
Vamos trazer para este formulário:
addToCart() {
this.$emit('add-to-cart');
},
O que tudo isso significa?
Então é isso. Quando o método é chamado
addToCart, um evento com nome personalizado é gerado add-to-cart. Ou seja, ao Add to cartclicar no botão , é chamado um método que gera um evento indicando que o botão acabou de ser pressionado (ou seja, que acaba de ocorrer o evento disparado pelo clique do botão).
Mas, agora, nada no aplicativo está esperando por esse evento, nem ouvindo por ele. Vamos adicionar um ouvinte de evento a
index.html:
<product :premium="premium" @add-to-cart="updateCart"></product>
Aqui, usamos a construção de visualização da
@add-to-cardmesma maneira que usamos a construção :premium. Mas se :premiumfor um "pipeline" por meio do qual os dados podem ser transmitidos ao componente filho do pai, @add-to-cartele pode ser comparado ao "receptor de rádio" do componente pai, que recebe informações do componente filho de que um botão foi pressionado Add to cart. Como o "rádio" está em uma tag <product>aninhada em <div id="app">, isso significa que, quando a informação sobre um clique chegar , o Add to cartmétodo updateCartlocalizado na instância raiz do Vue será chamado . Traduzido para a linguagem comum, o
código se
@add-to-cart=«updateCart»parece com este: "Quando você ouvir que um evento ocorreu add-to-cart, chame o método updateCart."
Este método, que agora será declarado no objeto options usado ao instanciar o Vue, você provavelmente viu em algum lugar:
methods: {
updateCart() {
this.cart += 1;
}
}
Na verdade, esse é exatamente o mesmo método usado anteriormente em
product. Mas agora ele está na instância raiz do Vue e é chamado com um clique de botão Add to cart.

Botão funciona novamente
Quando você clica em um botão que está em um componente
product, é chamado um métodoaddToCartque gera um evento. A instância raiz do Vue, ouvindo o rádio, descobre que o evento ocorreu e chama um métodoupdateCartque incrementa o número armazenado emcart.
Alcançamos nosso objetivo, mas em uma aplicação real, saber que ocorreu um evento, que determinado produto foi adicionado ao carrinho, não trará muito benefício. Na realidade, você precisa saber pelo menos qual produto foi adicionado ao carrinho. Isso significa que, no evento gerado em resposta ao pressionamento do botão, você também precisa transferir alguns dados.
Os dados passados no evento podem ser descritos como o segundo argumento passado
$emitno código do método doaddToCartcomponenteproduct:
this.$emit('add-to-cart', this.variants[this.selectedVariant].variantId);
Agora o evento passa o identificador (
variantId) do produto que o usuário deseja adicionar ao carrinho. Isso significa que em vez de apenas aumentar o número de itens no carrinho, podemos ir além e armazenar informações mais detalhadas sobre os itens adicionados a ele no carrinho. Para fazer isso, primeiro convertemos o carrinho em uma matriz, escrevendo uma matriz vazia para cart:
cart: []
A seguir, vamos reescrever o método
updateCart. Em primeiro lugar - agora ele aceitará id- o mesmo identificador de produto que agora é passado no evento, e em segundo lugar - ele agora colocará o que recebeu em uma matriz:
methods: {
updateCart(id) {
this.cart.push(id);
}
}
Após um único clique no botão, o identificador do produto é adicionado ao array. A matriz é exibida na página.

A matriz com o ID do produto é exibida na página
. Não precisamos exibir a matriz inteira na página. Ficaremos satisfeitos com a saída do número de produtos adicionados ao carrinho, ou seja, ao array
cart. Portanto, podemos reescrever o código da tag<p>, que exibe informações sobre a quantidade de produtos adicionados ao carrinho, assim:
<p>Cart({{ cart.length }})</p>

A página exibe informações sobre o número de itens adicionados ao carrinho.
Agora, simplesmente exibimos o comprimento do array na página, ou, em outras palavras, o número de itens no carrinho. Externamente, o carrinho tem a mesma aparência de antes, mas agora, em vez de simplesmente aumentar o valor de uma propriedade numérica
cart, armazenamos em uma matriz ascartinformações sobre qual item específico foi adicionado ao carrinho.
Oficina
Adicione um botão ao projeto que remove o
cartproduto adicionado anteriormente do array . Ao clicar neste botão, deve ser gerado um evento contendo informações sobre o identificador do produto a ser retirado do carrinho.
- Aqui está um modelo que você pode usar para resolver esse problema.
- Aqui está a solução para o problema.
Resultado
Aqui está o que você aprendeu hoje:
- Um componente pode informar à entidade pai que algo aconteceu nela usando a construção
$emit. - Um componente pai pode usar um manipulador de eventos especificado usando a diretiva
v-on(ou sua versão abreviada@) para organizar uma resposta a eventos gerados por componentes filhos. Se ocorrer um evento, um manipulador de eventos pode ser chamado no componente pai. - , , .
Se você está estudando o curso e chegou a esta lição, conte-nos sobre o propósito para o qual está fazendo, o que deseja alcançar ao dominar o Vue.
→ 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
