Vue.js para iniciantes lição 9: eventos personalizados

Na lição anterior em nosso curso Vue, você aprendeu como criar componentes e como passar dados de pai para filho usando o mecanismo de adereços. E se os dados precisarem ser transferidos na direção oposta? Hoje, na nona lição, você aprenderá como estabelecer uma comunicação bidirecional entre componentes de diferentes níveis.







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 emcart.



Para conseguir isso, vamos primeiro reescrever o código do método doaddToCartcomponenteproduct.



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 componenteproduct, é 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 arraycart. 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éricacart, 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.





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






All Articles