Verwenden Sie die Renderfunktion, um hoch skalierbare Komponenten zu kapseln

Verwenden Sie die Renderfunktion, um hoch skalierbare Komponenten zu kapseln

brauchen:

In der Hintergrundverwaltung gibt es häufig Anforderungen an die Datenanzeige mit folgendem Layout:

Es sieht aus wie eine Tabelle, ist aber keine Tabelle, und wie ein Formular, ist aber kein Formular. Tatsächlich sieht es wie eine Tabelle aus, und die dargestellten Daten sind ein Objekt, das mit dem gebundenen Wert des Formulars identisch ist. Ich nenne es eine Tabelle im Formularstil.

Die Spalten mit tiefen Stilen sind Titel, und die Spalten mit flachen Stilen sind die Werte, die den Titeln entsprechen. Die Daten werden häufig vom Server zurückgegeben, und die Titel haben häufig eine feste Breite. Die Werte können variieren. Wenn beispielsweise ein Bild angezeigt wird, ist der Wert 01, und Sie müssen „Ja“ oder „Nein“ anzeigen. Manchmal müssen Sie eine Änderungsschaltfläche hinzufügen, damit Benutzer bestimmte Werte ändern können, und Sie müssen auch festlegen, dass eine Spalte mehrere Spalten umfasst.

Schauen wir uns zunächst eine Implementierung basierend auf element ui an.

Schlechte Implementierung:

Ich habe in dem Projekt, das ich übernommen habe, eine Implementierung gesehen. Schauen wir uns zunächst an, wie man sie verwendet.

<FormTable :data="lessonPackageArr" :fleldsInfo="lessonPackageInfo" :maxColumn="3" label-width="120px">
  <template #presentedHours="{ data }">
    <div Klasse="Flex-Box zwischen">
      <span>
        {{ data.presentedHours }}
      </span>
      <span class="column-btn" @click="editPresentedHours(data)">Bearbeiten</span>
    </div>
  </Vorlage>
  <template #gifts="{ data }">
    <div Klasse="Flex-Box zwischen">
      <span>
        {{ data.gifts }}
      </span>
      <span class="column-btn" @click="editPresentedHours(data)">Bearbeiten</span>
    </div>
  </Vorlage>
</FormTable>


Das Objekt „lektionsPackageInfo“ hat die folgende Struktur:

// Ein Objekt, das zum Konfigurieren der Titelspalte und der entsprechenden Felder der Titelspalte verwendet wird // Typ gibt den Typ des Wertes an. Jetzt legt die Komponente intern fest, welche Arten von Werten angezeigt werden können // Für Dienste gibt es 1 0 zurück. Wenn eine Zahl angezeigt werden muss, geben Sie map_data an, um // Spaltenattributeinstellungen spaltenübergreifend zuzuordnen // Sie müssen den Anzeigeinhalt anpassen, um einen Slot bereitzustellen
Lektionspaketinfo: {
    orderType: { type: 'option', desc: 'Kurspaketkategorie', map_data: { 1: 'Erste Bestellung', 2: 'Verlängerung', 5: 'Kostenloser Kurs' } },
    Combo: { Typ: 'Text', Beschreibung: 'Paketname' },
    presentedHours: { type: 'text', desc: 'Freie Unterrichtsstunden', slot: true },
    Preis: { Typ: 'Text', Beschreibung: 'Standardpreis' },
    Geschenke: { Typ: 'Text', Beschreibung: 'Geschenk', Spalte: 3, Steckplatz: true },
  }


  • Props ist nicht intuitiv genug und hat viele Konfigurationselemente
  • Nicht vollständig datengesteuert

Warum ist es schlecht, zu viele Konfigurationselemente für eine Komponente zu haben?

Diese Anforderung ist sehr festgelegt. Die Komponenteneingabe, d. h. props , sollte minimiert, die Komponentenfunktion maximiert und für Requisiten so weit wie möglich Standardwerte bereitgestellt werden, um die Entwicklungseffizienz des Teams zu verbessern.

Warum ist es schlecht, nicht vollständig datengesteuert zu sein?

Diese Komponente ist nicht vollständig datengesteuert. Wenn Sie die Anzeigespalten anpassen müssen, müssen Sie eine Vorlage schreiben.

Wenn viele Spalten angepasst werden müssen, müssen Sie viele Vorlagencodes schreiben. Wenn Sie diese wieder extrahieren möchten, können Sie die Komponenten nur erneut kapseln. Wenn Sie sie nicht extrahieren, werden die Vorlagencodes möglicherweise erweitert. Sie sehen möglicherweise oft template mit 500 Zeilen pro Zeile? Der erweiterte Vorlagencode erschwert die Komponentenwartung, da ein Hin- und Herwechseln zwischen template und JS-Code erforderlich ist. Darüber hinaus müssen Sie zum Hinzufügen einer Spalte mit benutzerdefinierten Daten mindestens zwei Stellen ändern.

Warum müssen wir vollständig datengesteuert sein?

Obwohl es Slots zum Erweitern von Komponenten gibt, sollten wir diese beim Schreiben von Geschäftskomponenten weniger nutzen und stattdessen versuchen, datengesteuerte Vorlagen zu verwenden. Da es sich bei den Daten um JS-Code handelt, ist es bei der Erweiterung des Komponentencodes einfach, den JS-Code in eine separate Datei zu extrahieren. Wenn Sie den Slot-Code extrahieren möchten, können Sie die Komponente nur erneut kapseln.

Das Designkonzept der drei wichtigsten Front-End-Frameworks basiert auf datengesteuerten Vorlagen. Dies ist ein wichtiges Merkmal, das sie von jQuery unterscheidet, und auch das Prinzip, dem wir beim Kapseln von Geschäftskomponenten zuerst folgen.

Nachdem wir uns die Probleme bei der Komponentenverwendung angesehen haben, schauen wir uns nun den Komponentencode an:

<Vorlage>
  <div v-if="tableData.length" Klasse="form-table">
    <div v-for="(Daten, _) in Tabellendaten" :Schlüssel="_" Klasse="Tabellenborder">
      <el-row v-for="(Zeile, Index) in Zeilen" :key="Index">
        <el-col v-for="(Feld, Schlüssel) in Zeile" :key="Schlüssel" :span="getSpan(Feld.Spalte)">
          <div v-if="(field.disabled && data[key]) || !field.disabled" class="Spalteninhalt Flex-Box zwischen">
            <div Klasse="Beschriftung" :style="'Breite:' + Beschriftungsbreite">
              <span v-if="Feld.erforderlich" Klasse="erforderlich">*</span>
              {{ feld.desc }}
            </div>
            <div Klasse="Text Flex-Element" :title="Daten[Schlüssel]">
              <template v-if="Schlüssel === 'Mindestalter'">
                <span>{{ Daten[Schlüssel] }}</span>
                -
                <span>{{ Daten['maxAge'] }}</span>
              </Vorlage>
              <template v-else-if="Schlüssel === 'status'">
                <template v-if="Feld.statusList">
                  <span v-if="data[key] == 0" :class="field.statusList[2]">{{ field.map_data[data[key]] }}</span>
                  <span v-else-if="Daten[Schlüssel] == 10 || Daten[Schlüssel] == 34" :class="Feld.statusList[1]">
                    {{ field.map_data[data[key]] }}
                  </span>
                  <span v-else :class="field.statusList[0]">{{ field.map_data[data[key]] }}</span>
                </Vorlage>
                <span v-else>{{ Feld.map_data[Daten[Schlüssel]] }}</span>
              </Vorlage>

              <slot v-else :name="Schlüssel" v-bind:data="Daten">
                <Tabellenspalteninhalt
                  :dataType="Feld.Typ"
                  :metaData="Daten[Schlüssel]"
                  :mapData="Feld.map_data"
                  :text="Feld.text"
                />
              </slot>
            </div>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
  <div v-else class="form-table empty">Keine Daten</div>
</Vorlage>

<Skript>
  importiere TableColContent aus '@/components/TableColContent'
  Standard exportieren {
    Name: "FormTable",
    Komponenten:
      Tabellenspalteninhalt,
    },
    Requisiten: {
      // Daten: {
        erforderlich: wahr,
        Typ: [Objekt, Array, null],
      },
      // Feldinformationen fieldsInfo: {
        erforderlich: wahr,
        Typ: Objekt,
        // Klassenname: { Typ: "Text", Beschreibung: "Klassenname", Spalte: 3 },
      },
      // Maximale Anzahl anzuzeigender Spalten maxColumn: {
        erforderlich: false,
        Typ: Nummer,
        Standard: 2,
      },
      Beschriftungsbreite: {
        erforderlich: false,
        Typ: Zeichenfolge,
        Standard: '90px',
      },
    },
    Daten() {
      zurückkehren {}
    },
    berechnet: {
      Tabellendaten() {
        wenn (!diese.daten) {
          zurückkehren []
        }
        wenn (diese.Dateninstanzdes Arrays) {
          gib diese Daten zurück
        } anders {
          returniere [diese.Daten]
        }
      },
      Zeilen() {
        const returnArray = []
        sei total = 0
        lass Artikel = {}
        für (const key in this.fleldsInfo) {
          const nextTotal = total + this.fleldsInfo[Schlüssel].Spalte || 1
          wenn (nächstesTotal > diese.maxColumn) {
            returnArray.push(Element)
            Artikel = {}
            Gesamt = 0
          }
          Gesamt += this.fieldsInfo[Schlüssel].Spalte || 1
          item[Schlüssel] = this.fieldsInfo[Schlüssel]
          wenn (Gesamt === diese.maxColumn) {
            returnArray.push(Element)
            Artikel = {}
            Gesamt = 0
          }
        }
        wenn (gesamt) {
          returnArray.push(Element)
        }
        Rückgabewert returnArray
      },
    },
    Methoden: {
      getSpan(Spalte) {
        wenn (!Spalte) {
          Spalte = 1
        }
        Spalte zurückgeben * (24 / this.maxColumn)
      },
    },
  }
</Skript>

Was sind die Fragen?

  • Die Vorlage enthält zu viele bedingte Urteile, was nicht elegant ist
  • Um die Anzeigespalten anzupassen, müssen Sie auch TableColContent einführen, was die Komplexität der Komponente erhöht

TableColContent führt weiterhin eine bedingte Beurteilung des Typs des Konfigurationselements durch

Teil des Codes:

<span v-else-if="Datentyp === 'Bild' || Datentyp === 'Cropper'" :class="Klassenname">
  <el-popover placement="rechts" title="" trigger="hover">
    <img :src="metaData" style="max-width: 600px;" />
    <img slot="Referenz" :src="Metadaten" :alt="Metadaten" width="44" class="Spaltenbild" />
  </el-popover>
</span>


Nachdem wir die oben genannten Implementierungsprobleme analysiert haben, schauen wir uns die gute Implementierung an:

Gute Umsetzung:

Schauen Sie sich zunächst die Verwendung an:

<Vorlage>
  <ZmFormTable :titleList="Titelliste" :data="Daten" />
</Vorlage>
<Skript>
  Standard exportieren {
    Name: 'Test',
    Daten() {
      zurückkehren {
        data: {}, // Titelliste vom Server abrufen: [
          { Titel: 'Name', Eigenschaft: 'Name', Spanne: 3 },
          {
            Titel: 'Classroom Works',
            Eigenschaft: (h, Daten) => {
              const img =
                (Daten.Arbeitsbild && (
                  <ElBild
                    Stil = 'Breite: 100px; Höhe: 100px;'
                    src={data.workPic}
                    Vorschau-Quellenliste={[data.workPic]}
                  ></ElImage>
                )) ||
                ''
              Bild zurückgeben
            },
            Spanne: 3,
          },
          { title: 'Arbeitskommentare', prop: 'workComment', span: 3 },
        ],
      }
    },
  }
</Skript>


Komponentenbeschreibung: titleList ist die Spaltenkonfiguration der Komponente, ein Array. Das Element-Titelattribut ist der Titel, prop gibt das aus den Daten zu übernehmende Feld an und span gibt die Anzahl der Zeilen an, die dieser Spaltenwert umfasst.

prop unterstützt string und Funktionen, wodurch eine benutzerdefinierte Anzeige erreicht werden kann. Wenn diese Funktion sehr groß ist, kann sie in eine separate JS-Datei extrahiert werden, oder die gesamte titleList kann in eine separate JS-Datei extrahiert werden.

Wie werden die Parameter h und Daten übergeben? Oder wo wird diese Funktion aufgerufen?

h ist die Funktion createElement , data sind die Daten aus dem Inneren der Komponente und es handelt sich um denselben Wert wie die von der übergeordneten Komponente übergebenen Daten.

Wenn das erste Argument einer normalen Funktion h ist, handelt es sich um eine render .

Diese Methode ist viel einfacher anzuwenden.

Schauen Sie sich die interne Implementierung an:

 <Vorlage>
  <div Klasse="Formulartabelle">
    <ul v-if="Titelliste.Länge">
      <!-- titleInfo ist die transformierte Titelliste-->
      <li
        v-for="(Element, Index) in Titelinfo"
        :Schlüssel="Index"
        :style="{ width: ((item.span || 1) / titleNumPreRow) * 100 + '%' }"
      >
        <div Klasse = "form-table-title" :style = "`Breite: ${titleWidth}px;`">
          <Container v-if="Typ von item.title === 'Funktion'" :renderContainer="item.title" :data="Daten" />
          <span v-else>
            {{ item.title }}
          </span>
        </div>
        <div class="form-table-key" :style="`width:calc(100% - ${titleWidth}px);`">
          <Container v-if="Typ von item.prop === 'Funktion'" :renderContainer="item.prop" :data="Daten" />
          <span v-else>
            {{ ![null, void 0].includes(data[item.prop] && data[item.prop]) || '' }}
          </span>
        </div>
      </li>
    </ul>
    <div v-else class="form-table-no-data">Keine Daten</div>
  </div>
</Vorlage>

<Skript>
  Container aus „./container.js“ importieren
  Standard exportieren {
    Name: "FormTable",
    Komponenten:
      Container,
    },
    Requisiten: {
      Titelbreite: {
        Typ: Nummer,
        Standard: 120,
      },
      TitelAnzahlVorZeile: {
        Typ: Nummer,
        Standard: 3,
        Validator: Wert => {
          const validate = [1, 2, 3, 4, 5, 6].includes(Wert)
          wenn (!validieren) {
            console.error('titleNumPreRow gibt an, dass eine Zeile ein Titelfeldpaar hat, das nur eine gerade Zahl zwischen 1 und 6 sein kann, der Standardwert ist 3')
          }
          zurückgeben validieren
        },
      },
      Titelliste: {
        Typ: Array,
        Standard: () => {
          zurückkehren []
        },
        Validator: Wert => {
          const validate = Wert.jedes(Element => {
            const { Titel, Eigenschaft } = Artikel
            Titel und Eigenschaft zurückgeben
          })
          wenn (!validieren) {
            console.log('Das Element des übergebenen titleList-Attributs muss die Attribute title und prop enthalten.')
          }
          zurückgeben validieren
        },
      },
      Daten: {
        Typ: Objekt,
        Standard: () => {
          zurückkehren {}
        },
      },
    },
  }
</Skript>
<!-- Stil ist nicht kritisch, wird weggelassen-->

Die benutzerdefinierte Anzeige wird nicht über dynamische Slots implementiert, sondern über die Funktionskomponente Container , die eine render als prop erhält.

Standard exportieren {
  Name: 'Container',
  funktional: wahr,
  rendern(h, { Eigenschaften }) {
    returniere props.renderContainer(h, props.data)
  },
}

Rufen Sie die von titleList im Container übergebene Funktion auf.

Zusammenfassen:

  • Priorisieren Sie datengesteuerte Komponenten beim Verpacken
  • Der erste Parameter einer normalen Funktion ist h, die Rendering-Funktion.
  • Manche Leute sind vielleicht nicht daran gewöhnt, JSX zu schreiben, aber beide Schreibmethoden sind kompatibel.

Dies ist das Ende dieses Artikels über die Verwendung der Renderfunktion zum Einkapseln hochskalierbarer Komponenten. Weitere relevante Inhalte zur Verwendung der Renderfunktion zum Einkapseln hochskalierbarer Komponenten finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Verwendung der VUE-Renderfunktion und ausführliche Erklärung
  • Vues Render-Funktion
  • Detaillierte Erklärung zur Verwendung der Vue.js-Renderfunktion
  • Festlegen der Ref-Operation für Unterkomponenten über die Renderfunktion in Vue
  • Die Vue-Renderfunktion lädt den Quellpfadvorgang von img dynamisch
  • Funktionsprinzip von Vue Render und Codebeispielanalyse
  • Detaillierte Erklärung der Renderfunktion in Vue

<<:  Analyse des zugrunde liegenden Prinzips der MySQL-Mehrversions-Parallelitätskontrolle MVCC

>>:  Der Prozess der Installation von Docker im Linux-System

Artikel empfehlen

js+css zur Realisierung eines dreistufigen Navigationsmenüs

In diesem Artikelbeispiel wird der spezifische Co...

React antd realisiert dynamische Vergrößerung und Verkleinerung der Form

Beim Schreiben dynamischer Formulare bin ich zuvo...

Swiper+echarts realisiert den Links- und Rechts-Scrolleffekt mehrerer Dashboards

In diesem Artikel wird der spezifische Code von S...

Zusammenfassung der Mysql Hochleistungsoptimierungsfähigkeiten

Datenbank-Befehlsspezifikation Alle Datenbankobje...

So ändern Sie das ursprüngliche Passwort von MySQL auf dem MAC

Problembeschreibung: Ich habe einen Mac gekauft u...

Mehrere Methoden zum Löschen von Floating (empfohlen)

1. Fügen Sie ein leeres Element desselben Typs hi...

Einführung in den glibc-Upgradeprozess für Centos6.5

Inhaltsverzeichnis Szenarioanforderungen glibc-Ve...

Beispielcode zur Realisierung des Ladeeffekts der B-Station mit CSS+SVG

Schwierigkeit Erstellung von zwei Masken für SVG-...

Frameset über Iframe in Body einfügen

Da Frameset und Body auf derselben Ebene liegen, k...

Drei Möglichkeiten zum Erstellen eines Graueffekts auf Website-Bildern

Ich habe schon immer Graustufenbilder bevorzugt, d...