Verwenden von Slots in Vue als Beispiel für ein Produkt-Snippet

Bei der Arbeit mit Projekten, bei denen SSR (Server Side Rendering) nicht verwendet wird oder nicht implementiert werden kann, tritt das Problem auf, dass einige Funktionen oder Logik für statische Elemente, die das Backend druckt, und für Komponenten, die Vue rendern, zweimal geschrieben werden.

Zum Beispiel müssen wir eine Produkt-Snippet-Komponente implementieren, die eine Reihe von Anforderungen stellt:

  • Es kann statisch aus dem Backend mit allen notwendigen Informationen für SEO und Logik gedruckt werden.
  • Es kann als reguläre Vue-Komponente verwendet werden, um Parameter über v-bind zu übergeben, Klickereignisse anzuhängen usw.
  • Es sollte den aktuellen Status der Schaltfläche "Kaufen" anzeigen
  • Nach dem Klicken auf die Schaltfläche "Kaufen" sollte ein Preloader erscheinen, der auf den Status des Warenkorbs wartet

Eine Lösung:

  1. Schreiben Sie Logik für statische Snippets, indem Sie Klickereignisse anhängen, Ladeklassen über die Schaltfläche Kaufen hinzufügen und entfernen
  2. Schreiben Sie separat eine Komponente in Vue, die dieselbe Logik nur im Vorlagenformat implementiert
  3. Verwenden Sie das erste Element, um vom Backend auszugeben, das zweite, um beispielsweise saubere Daten auszugeben, die aus state oder ajax stammen

Wir werden also zwei Logiken schreiben, eine arbeitet direkt mit dem DOM, die andere mit reinen Daten.

Meine Lösung für dieses Problem besteht darin, Slots zu verwenden, nämlich die Möglichkeit, den Standardinhalt festzulegen, der dynamische Parameter enthält. Wenn die Komponente jedoch als Inline-Vorlage verwendet wird, werden alle diese Parameter durch die vom Backend gezeichneten ersetzt.

Schreiben wir eine Komponente, die sowohl Statik als auch Dynamik verarbeiten kann:

Komponentenliste
<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> 


Verwenden einer Komponente über das 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> 

Verwenden einer Komponente in anderen Komponenten:

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

Jetzt haben wir eine Komponente, die in verschiedenen Fällen verwendet werden kann.

Ich würde gerne Ihre Meinung zu diesem Ansatz hören, vielleicht gibt es eine bessere Lösung.

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


All Articles