→ Vue.js principiantes lección 1: instancia Vue
→ Vue.js para principiantes, lección 2: atributos de enlace
→ Vue.js principiantes lección 3: renderizado condicional
→ Vue.js principiantes lección 4: listas de renderización
→ Vue .js para principiantes lección 5: procesamiento de eventos
→ Vue.js principiantes lección 6: clases y estilos vinculantes
→ Vue.js principiantes lección 7: propiedades calculadas
→ Vue.js principiantes lección 8: componentes
→ Vue. js para principiantes lección 9: eventos personalizados
El propósito de la lección
Queremos que el componente
product
pueda notificar a la entidad principal, la instancia raíz de Vue, que ha ocurrido un evento. En este caso, product
deberá enviar, junto con la notificación de la ocurrencia del evento, algunos datos.
Código inicial
El archivo de
index.html
proyecto de muestra ahora contiene el siguiente código:
<div id="app">
<product :premium="premium"></product>
</div>
Aquí está el contenido del archivo
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
}
})
Tarea
Ahora que se
product
presenta como un componente independiente, no product
tiene sentido que el código relacionado con el carrito esté en él. Si cada producto tiene su propia canasta de la que necesitamos monitorear el estado, nuestra aplicación se convertirá en un gran desastre. En cambio, nos gustaría que el carrito existiera en la raíz de la instancia de Vue. También necesitamos el componente para product
informar a la instancia raíz de Vue sobre cómo agregar artículos al carrito, es decir, sobre los clics en el botón Add to cart
.
Decisión
Muevamos los datos relacionados con el carrito de regreso a la instancia raíz de Vue:
var app = new Vue({
el: '#app',
data: {
premium: true,
cart: 0
}
})
A continuación, volvamos a mover la plantilla del carrito
index.html
, llevando su código a este formulario:
<div id="app">
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
<product :premium="premium"></product>
</div>
Ahora, si abre la página de la aplicación en un navegador y hace clic en el botón
Add to cart
, no sucede nada como se esperaba.
Hacer clic en el botón Agregar al carrito no conduce a nada todavía
¿Qué debería suceder cuando se hace clic en este botón? Necesitamos que al hacer clic en él, la instancia raíz de Vue reciba una notificación que llame a un método que actualice el carrito, es decir, actualice el valor que está almacenado
cart
.
Para lograr esto, primero reescribamos el código del método del
addToCart
componenteproduct
.
Ahora se ve así:
addToCart() {
this.cart += 1;
},
Llevémoslo a este formulario:
addToCart() {
this.$emit('add-to-cart');
},
¿Qué significa todo esto?
Entonces eso es lo que es. Cuando se llama al método
addToCart
, se genera un evento con nombre personalizado add-to-cart
. En otras palabras, cuando Add to cart
se hace clic en un botón , se llama a un método que genera un evento que indica que el botón se acaba de presionar (es decir, que el evento desencadenado por el clic del botón acaba de ocurrir).
Pero en este momento, nada en la aplicación espera este evento, no lo está escuchando. Agreguemos un detector de eventos a
index.html
:
<product :premium="premium" @add-to-cart="updateCart"></product>
Aquí usamos la construcción de vista de la
@add-to-card
misma manera que usamos la construcción :premium
. Pero si se :premium
trata de una "canalización" a través de la cual se pueden transmitir datos al componente secundario desde el principal, entonces @add-to-cart
se puede comparar con el "receptor de radio" del componente principal, que recibe información del componente secundario de que se ha presionado un botón Add to cart
. Dado que la "radio" está en una etiqueta <product>
anidada <div id="app">
, esto significa que cuando llega información sobre un clic , Add to cart
se llamará updateCart
al método ubicado en la instancia raíz de Vue. Traducido al lenguaje ordinario, el
código se
@add-to-cart=«updateCart»
ve así: "Cuando escuche que ha ocurrido un evento add-to-cart
, llame al método updateCart
".
Este método, que ahora se declarará en el objeto de opciones utilizado al crear una instancia de Vue, probablemente lo haya visto en alguna parte:
methods: {
updateCart() {
this.cart += 1;
}
}
De hecho, este es exactamente el mismo método que se utilizó anteriormente
product
. Pero ahora está en la instancia raíz de Vue y se llama al hacer clic en un botón Add to cart
.
El botón funciona de nuevo
Cuando hace clic en un botón ubicado en un componente
product
, se llama a un métodoaddToCart
que genera un evento. La instancia raíz de Vue, escuchando la radio, se entera de que el evento ha ocurrido y llama a un métodoupdateCart
que incrementa el número almacenado encart
.
Logramos nuestro objetivo, pero en una aplicación real, saber que ha ocurrido un evento, que se ha añadido un determinado producto al carrito, no traerá mucho beneficio. En realidad, necesita saber al menos qué producto se agregó al carrito. Esto significa que en el caso de que se genere en respuesta a presionar el botón, también es necesario transferir algunos datos.
Los datos pasados en el evento se pueden describir como el segundo argumento pasado
$emit
en el código del método deladdToCart
componente.product
:
this.$emit('add-to-cart', this.variants[this.selectedVariant].variantId);
Ahora el evento pasa el identificador (
variantId
) del producto que el usuario quiere agregar al carrito. Esto significa que, en lugar de simplemente aumentar la cantidad de artículos en el carrito, podemos ir más allá y almacenar información más detallada sobre los artículos agregados en el carrito. Para hacer esto, primero convertimos la canasta en una matriz escribiendo una matriz vacía en cart
:
cart: []
A continuación, reescribamos el método
updateCart
. En primer lugar, ahora aceptará id
el mismo identificador de producto que ahora se pasa en el evento, y en segundo lugar, ahora pondrá lo que recibió en una matriz:
methods: {
updateCart(id) {
this.cart.push(id);
}
}
Después de un solo clic en el botón, el identificador de producto se agrega a la matriz. La matriz se muestra en la página.
La matriz con el ID del producto se muestra en la página
. No es necesario mostrar la matriz completa en la página. Estamos satisfechos con la salida de la cantidad de productos agregados al carrito, es decir, a la matriz
cart
. Por lo tanto, podemos reescribir el código de la etiqueta<p>
, que muestra información sobre la cantidad de productos agregados al carrito, de la siguiente manera:
<p>Cart({{ cart.length }})</p>
La página muestra información sobre la cantidad de artículos agregados al carrito.
Ahora simplemente mostramos la longitud de la matriz en la página o, en otras palabras, la cantidad de artículos en el carrito. Externamente, el carrito se ve igual que antes, pero ahora, en lugar de simplemente aumentar el valor de una propiedad numérica
cart
, almacenamos en una matrizcart
información sobre qué artículo se agregó al carrito.
Taller
Agregue un botón al proyecto que elimine el
cart
producto agregado allí anteriormente de la matriz . Al hacer clic en este botón, se debe generar un evento que contenga información sobre el identificador del producto que se eliminará del carrito.
- Aquí hay una plantilla que puede usar para resolver este problema.
- Aquí está la solución al problema.
Salir
Esto es lo que aprendiste hoy:
- Un componente puede informar a la entidad padre que algo ha sucedido en él usando la construcción
$emit
. - Un componente principal puede utilizar un controlador de eventos especificado mediante la directiva
v-on
(o su versión abreviada@
) para organizar una respuesta a los eventos generados por los componentes secundarios. Si ocurre un evento, se puede llamar a un controlador de eventos en el componente principal. - , , .
Si está estudiando el curso y ha llegado a esta lección, cuéntenos sobre el propósito por el que está haciendo, lo que quiere lograr al dominar Vue.
→ Vue.js principiantes lección 1: instancia Vue
→ Vue.js para principiantes, lección 2: atributos de enlace
→ Vue.js principiantes lección 3: renderizado condicional
→ Vue.js principiantes lección 4: listas de renderización
→ Vue .js para principiantes lección 5: procesamiento de eventos
→ Vue.js principiantes lección 6: clases y estilos vinculantes
→ Vue.js principiantes lección 7: propiedades calculadas
→ Vue.js principiantes lección 8: componentes
→ Vue. js para principiantes lección 9: eventos personalizados