Usar slots en Vue como ejemplo de un fragmento de producto

Cuando se trabaja con proyectos donde no se usa SSR (Representación del lado del servidor) o no es posible implementarlo, surge el problema de que algunas funciones o lógica se escriben dos veces para elementos estáticos que imprime el backend y para componentes que representan Vue.

Por ejemplo, necesitamos implementar un componente de fragmento de producto que tenga varios requisitos:

  • Se puede imprimir estáticamente desde el backend con toda la información necesaria para SEO y lógica.
  • Se puede usar como un componente Vue normal, pasando parámetros a través de v-bind, adjuntando eventos de clic , etc.
  • Debería mostrar el estado actual del botón de compra
  • Después de hacer clic en el botón "Comprar", aparecerá un precargador esperando el estado de la cesta

Una solución:

  1. Escriba lógica para fragmentos estáticos adjuntando eventos de clic, agregue y elimine clases de carga en el botón Comprar
  2. Escriba por separado un componente en Vue que implemente la misma lógica solo en formato de plantilla
  3. Use el primer elemento para generar desde el backend, el segundo, por ejemplo, para generar datos limpios obtenidos de state o ajax

Por lo tanto, escribiremos dos lógicas, una trabajará directamente con el DOM y la otra con datos puros.

Mi solución a este problema es usar ranuras, es decir, la capacidad de establecer el contenido predeterminado, que contendrá parámetros dinámicos, pero al mismo tiempo si el componente se usa como una plantilla en línea, todos estos parámetros serán reemplazados por aquellos dibujados por el backend.

Escribamos un componente que pueda manejar tanto la estática como la dinámica:

Listado de componentes
<template> <div> <!--   image   ,       --> <slot name="image"> <!--    --> <a :href="url" class="snippet__image"> <img :src="image"> </a> </slot> <slot name="title"> <a :href="url" class="snippet__title">{{ title }}</a> </slot> <div v-if="!inCart" @click="add" :class="{ 'snippet__buy--load': load }" class="snippet__control" > <slot name="button"> <div class="snippet__button"></div> </slot> </div> <div v-if="inCart" class="snippet__control"> <div class="snippet__button"></div> </div> <div v-if="load" class="snippet__load"></div> </div> </template> <script> //  vuex     import { mapState, mapActions } from 'vuex' export default { props: { id: { type: Number, required: true }, url: { type: String }, image: { type: String }, title: { type: String } }, data() { return { //   load: false, //     inCart: false, } }, computed: { ...mapState({ //     cartItems: ({cart}) => cart.items }), }, mounted() { this.$nextTick(() => { //      this.inCart = this.cartItems.some(item => item.id === this.id) }) }, methods: { ...mapActions([ //     'addToCart' ]), add() { //    this.load = true //   this.addToCart({ id: this.id }) } }, watch: { //      cartItems(items) { //    this.load = false //      this.inCart = items.some(item => item.id === this.id) } } } </script> 


Usando un componente vía backend:

 <snippet :id="1" class="snippet"> <a slot="image" href="#" class="snippet__image"> <img src="photo.jpg"> </a> <a slot="title" href="#" class="snippet__title"> 1</a> <div slot="button" class="snippet__button"></div> </snippet> 

Usando un componente en otros componentes:

 <catalog-list> <snippet v-for="item in items" :key="item.id" v-bind="item"></snippet> </catalog-list> 

Ahora tenemos un componente que puede usarse en diferentes casos.

Me gustaría escuchar su opinión sobre este enfoque, tal vez haya una mejor solución.

Source: https://habr.com/ru/post/es422465/


All Articles