Vue-Beispielcode zur einfachen Implementierung von virtuellem Scrollen

Vue-Beispielcode zur einfachen Implementierung von virtuellem Scrollen

Vorwort

Bei der täglichen Entwicklung mobiler Webseiten gibt es gelegentlich Szenarien, in denen lange Listen gerendert werden müssen. Beispielsweise muss eine Reisewebsite die vollständige Liste der Städte im ganzen Land anzeigen und dann alle Namen im Adressbuch in alphabetischer Reihenfolge A, B, C usw. anzeigen.

Im Allgemeinen treten keine unerwarteten Effekte auf, wenn die Anzahl der langen Listen im Bereich von einigen Hundert liegt und der Browser selbst ausreichend ist, um sie zu unterstützen. Sobald die Anzahl jedoch Tausende erreicht, bleibt der Seiten-Rendering-Prozess offensichtlich hängen. Wenn die Anzahl Zehntausende oder sogar Hunderttausende überschreitet, kann die Webseite direkt abstürzen.

Um den durch lange Listen verursachten Rendering-Druck zu lösen, hat die Branche eine entsprechende Reaktionstechnologie entwickelt, nämlich das virtuelle Scrollen langer Listen.

Das Wesentliche beim virtuellen Scrollen ist, dass das HTML-Dokument unabhängig davon, wie die Seite gleitet, nur eine kleine Anzahl von DOM-Elementen rendert, die im aktuellen Bildschirm-Ansichtsfenster angezeigt werden.

Angenommen, eine lange Liste enthält 100.000 Daten, dann sieht der Benutzer nur etwa ein Dutzend Daten auf dem Bildschirm. Wenn die Seite gleitet, kann der Bildlaufeffekt daher stark simuliert werden, indem auf das Bildlaufereignis geachtet und die Ansichtsfensterdaten schnell umgeschaltet werden.

Beim virtuellen Scrollen muss nur eine kleine Anzahl von DOM-Elementen gerendert werden, um einen ähnlichen Scroll-Effekt zu simulieren. Dadurch können Front-End-Ingenieure lange Listen mit Zehntausenden oder sogar Hunderttausenden von Elementen entwickeln.

Das folgende Bild zeigt eine lange Liste von Städten auf der ganzen Welt, die auf einem Mobiltelefon angezeigt werden können (der Quellcode befindet sich am Ende des Artikels).

Rollprinzip

Um zu verstehen, wie virtuelles Scrollen funktioniert, schauen Sie sich zunächst das folgende Bild an. Wenn Sie Ihren Finger nach unten bewegen, wird die HTML-Seite auch nach oben gescrollt.
Aus den im Bild markierten Abständen können wir folgende Schlussfolgerung ziehen: Wenn die Oberkante des Bildschirm-Ansichtsfensters mit der Oberkante des Div-Elements mit der ID item übereinstimmt, entspricht die Distanz zwischen dem item-Element und der Oberseite der langen Liste genau der scrollTop-Distanz der Seite (diese Schlussfolgerung wird später bei der Berechnung der Distanz verwendet).

Um einen realistischen Scroll-Effekt zu simulieren, sollte das virtuelle Scrollen zunächst die folgenden beiden Anforderungen erfüllen.

  • Die Bildlaufleiste der virtuellen Bildlaufliste entspricht der der normalen Liste. Wenn die Liste beispielsweise 1.000 Datenelemente enthält und der Browser die normale Rendering-Methode verwendet, wird angenommen, dass die Bildlaufleiste 5.000 Pixel nach unten gescrollt werden muss, um unten angebracht zu werden. Nach der Anwendung der virtuellen Bildlauftechnologie sollte die Bildlaufleiste dieselben Eigenschaften aufweisen und 5.000 Pixel nach unten gescrollt werden, um unten angebracht zu werden.
  • Beim virtuellen Scrollen werden nur das Ansichtsfenster und einige DOM-Elemente auf der oberen und unteren Seite gerendert. Wenn die Bildlaufleiste nach unten gleitet, muss der Inhalt der Ansicht in Echtzeit aktualisiert werden, um sicherzustellen, dass der angezeigte Inhalt mit dem übereinstimmt, der beim normalen Rendern einer langen Liste angezeigt wird.

Um die oben genannten Anforderungen zu erfüllen, ist die HTML-Entwurfsstruktur wie folgt.

.wrapper ist das äußerste Containerelement, die Position wird auf absolut oder relativ eingestellt und die Position der untergeordneten Elemente wird darauf basierend festgelegt.

Die Unterelemente .background und .list sind der Schlüssel zum virtuellen Scrollen. .background ist ein leeres div, muss aber auf eine Höhe eingestellt werden, die der Summe der Höhen aller Listenelemente in der langen Liste entspricht. Darüber hinaus muss es auf absolute Positionierung und den Z-Index-Wert auf -1 eingestellt werden.

.list ist für das dynamische Rendern der vom Ansichtsfenster beobachteten Dom-Elemente verantwortlich und die Position ist auf absolut eingestellt.

<Vorlage>
  <div Klasse="Wrapper">
    <div Klasse="Hintergrund" :style="{height:`${total_height}px`}"></div>
    <div Klasse="Liste">
      <div Klasse="Zeile">
        <div class="item lt">PEKING</div>
        <div class="item gt">Peking</div>
      </div>
      <div Klasse="Zeile">
        <div class="item lt">shanghai</div>
        <div class="item gt">Schanghai</div>
      </div>
      <div Klasse="Zeile">
        <div class="item lt">Guangzhou</div>
        <div class="item gt">Guangzhou</div>
      </div>
      ... //Ausgelassen</div>
  </div>
</Vorlage>
<style lang="scss" scoped>
.wrapper {
  Position: absolut;
  links: 0;
  rechts: 0;
  unten: 0;
  oben: 60px;
  Überlauf-y: scrollen;
  .Hintergrund {
    Position: absolut;
    oben: 0;
    links: 0;
    rechts: 0;
    z-Index: -1;
  }
  .Liste {
    Position: absolut;
    oben: 0;
    links: 0;
    rechts: 0;
  }
}
</Stil>

Wenn die Gesamthöhe im obigen Code 10.000 Pixel beträgt, sieht das Diagramm mit den Seitenlaufeffekten wie folgt aus.
Da die Höhe des untergeordneten Elements .background festgelegt ist, wird das übergeordnete Element .wrapper vom untergeordneten Element unterstützt und eine Bildlaufleiste wird angezeigt.
Wenn Sie zu diesem Zeitpunkt nach unten schieben, scrollen die beiden untergeordneten Elemente .background und .list gleichzeitig nach oben. Wenn die Bildlaufdistanz 9324 Pixel erreicht, erreicht auch die Bildlaufleiste den Boden.
Dies liegt daran, dass das übergeordnete Element .wrapper selbst 676 Pixel hoch ist. Plus der Gleitdistanz von 9324 Pixeln entspricht das Ergebnis genau der Gesamthöhe der Liste von 10000 Pixeln.
Durch Beobachtung des obigen Verhaltens können wir erkennen, dass, obwohl .background nur ein leeres Div ist, die Bildlaufleiste auf der rechten Seite in Aussehen und Verhalten mit der Bildlaufleiste konsistent gehalten werden kann, die durch die normale Darstellung langer Listen generiert wird, indem man ihr die Gesamthöhe der Liste gibt.

Das Problem mit der Bildlaufleiste ist gelöst, aber wenn die Bildlaufleiste nach unten gleitet, bewegt sich die Datenliste nach oben. Nachdem die Liste vollständig aus dem Bildschirm verschoben wurde, ist der nächste Bildschirm vollständig weiß.
Um das Problem des weißen Bildschirms zu lösen, muss das Ansichtsfenster immer die gleitenden Daten anzeigen. Dann sollte das .list-Element seinen eigenen absolut positionierten oberen Wert dynamisch entsprechend der Gleitdistanz aktualisieren, um sicherzustellen, dass die .list nicht außerhalb des Bildschirms gezeichnet wird. Gleichzeitig sollten die Daten, die im aktuellen Ansichtsfenster angezeigt werden sollen, dynamisch entsprechend der Gleitdistanz gerendert werden.

Beachten Sie die folgende Animation, die Dom-Struktur rechts zeigt die Veränderungen beim Gleiten.

Nachdem die Bildlaufleiste schnell nach unten gerutscht ist, wird das DOM-Element der Liste schnell gerendert und aktualisiert. Zu diesem Zeitpunkt wird nicht nur das DOM-Element innerhalb der .list ständig ersetzt, sondern das .list-Element selbst ändert auch ständig den Stilwert transform: translate3d (0, ? px, 0) (das Ändern von translate3d kann einen ähnlichen Effekt erzielen wie das Ändern des obersten Attributwerts).

Nach der obigen Erklärung ist die Implementierungslogik des virtuellen Scrollens klar. Zuerst überwacht js das Gleitereignis der Bildlaufleiste und berechnet dann, welche Unterelemente des .list-Elements anhand der Gleitdistanz gerendert werden sollen, und aktualisiert dann die Position des .list-Elements. Wenn die Bildlaufleiste weiter gleitet, werden auch die Unterelemente und Positionen ständig aktualisiert und der Bildlaufeffekt wird im Ansichtsfenster simuliert.

erreichen

Die entwickelte Demoseite ist in der folgenden Abbildung dargestellt. Die Listenelemente enthalten die folgenden drei Strukturen:

  • Kleine Listenelemente, der erste Buchstabe der Stadt steht in einer separaten Zeile mit einer Höhe von 50px;
  • Gewöhnliche Listenelemente, englischer Name links, chinesischer Name rechts, Höhe 100px;
  • Großes Listenelement, mit englischem Namen links, chinesischem Namen in der Mitte und einem Bild rechts, mit einer Höhe von 150px;

Die JSON-Struktur der Listendaten „city_data“ ähnelt der folgenden. Typ 1 stellt die Stilstrukturdarstellung kleiner Listenelemente dar, 2 stellt normale Listenelemente dar und 3 stellt große Listenelemente dar.

[{"name":"A","value":"","typ":1},{"name":"Al l'Ayn","value":"Ayn","typ":2},{"name":"Aana","value":"Aana","typ":3} ... ]

city_data enthält alle Daten in der langen Liste. Nachdem wir city_data erhalten haben, durchlaufen und passen wir zunächst die Datenstruktur jedes Elements an (der Code lautet wie folgt).

Durch die folgende Verarbeitung erhält jedes Listenelement schließlich einen oberen und einen Höhenwert. Der obere Wert gibt die Länge des Elements vom Anfang der langen Liste an, und der Höhenwert bezieht sich auf die Höhe des Elements.
total_height ist die Gesamthöhe der gesamten Liste, die schließlich dem oben erwähnten .background-Element zugewiesen wird. Die verarbeiteten Daten werden zur Speicherung this.list zugewiesen und die Höhe des minimalen Listenelements this.min_height wird aufgezeichnet.

  montiert () {
     Funktion getHeight (Typ) { // Gibt die Höhe entsprechend dem Typwert zurück switch (Typ) {
          Fall 1: 50 zurückgeben;
          Fall 2: Gib 100 zurück;
          Fall 3: 150 zurückgeben;
          Standard:
            zurückkehren "";
        }
      }
      sei Gesamthöhe = 0;
      const list = city_data.map((Daten, Index) => {
        const Höhe = getHeight(Datentyp);
        const ob = {
          Index,
          Höhe,
          oben: Gesamthöhe,
          Daten
        }
        Gesamthöhe += Höhe;
        Rückkehr ob;
      })
      this.total_height = total_height; // Gesamthöhe der Liste this.list = list;
      this.min_height = 50; // Die Mindesthöhe beträgt 50
      //Die maximale Anzahl von Listenelementen, die der Bildschirm aufnehmen kann, containerHeight ist die Höhe des übergeordneten Containers, berechnet entsprechend der Mindesthöhe this.maxNum = Math.ceil(containerHeight / this.min_height);
  }

HTML rendert je nach Typwert unterschiedliche Stilstrukturen (Code wie folgt). Der übergeordnete Container .wrapper bindet ein Gleitereignis onScroll, und das Listenelement .list durchläuft das Array this.list nicht, da this.list die Originaldaten sind, die alle Listenelemente enthalten.

Die Vorlage <template> muss nur die Daten-RunList durchlaufen, die im Ansichtsfenster angezeigt werden müssen. Die im Array-RunList enthaltenen Daten werden mit dem Scroll-Ereignis kontinuierlich aktualisiert.

<Vorlage>
  <div Klasse="Wrapper" ref="Wrapper" @scroll="onScroll">
    <div Klasse="Hintergrund" :style="{height:`${total_height}px`}"></div>
    <div Klasse="Liste" ref="Container">
      <div v-for="Element in runList" :class="['line',getClass(item.data.type)]" :key="Element">
        <div class="item lt">{{item.data.name}}</div>
        <div class="item gt">{{item.data.value}}</div>
        <div v-if="item.data.type == 3" class="img-container">
          <img src="../../assets/default.png" />
        </div>
      </div>
    </div>
  </div>
</Vorlage>

Das Scroll-Ereignis löst die onScroll-Methode aus (Code wie folgt). Da die Bildlaufleiste sehr häufig ausgelöst wird, wird die Funktion requestAnimationFrame zum Drosseln verwendet, um den Rechenaufwand des Browsers zu reduzieren.

Das Scroll-Ereignisobjekt e kann die Distanz ermitteln, über die die aktuelle Bildlaufleiste gleitet. Basierend auf der Distanz müssen wir nur die Listendaten von runList berechnen und die Positionsinformationen von .list ändern.

 beimScrollen (e) {
      wenn (dieses.ticken) {
        zurückkehren;
      }
      dies.ticking = wahr;
      requestAnimationFrame(() => {
        dies.ticking = falsch;
      })
      Konstante Entfernung = e.target.scrollTop;
      diese.Entfernung = Entfernung;
      this.getRunData(Entfernung);
 }

Wie können wir schnell das erste Listenelement finden, das basierend auf der Bildlaufdistanz unter dem Bildschirmansichtsfenster gerendert werden soll?

this.list ist die Datenquelle der langen Liste, wobei jedes Listenelement seinen Abstand vom Anfang der langen Liste und seine eigene Höhe (height) speichert.
Eine der oben erwähnten Schlussfolgerungen besteht darin, dass beim Scrollen einer Seite die Gleitdistanz „scrollTop“ genau der Distanz vom Listenelement zum Anfang der langen Liste entspricht, wenn die Oberkante des Ansichtsfensters mit der Oberkante eines Listenelements zusammenfällt.

Wenn die Seite ein wenig nach oben verschoben wird, wird nur ein Teil des ersten Listenelements unter dem Ansichtsfenster angezeigt und der andere Teil befindet sich außerhalb des Bildschirms. Zu diesem Zeitpunkt stellen wir immer noch fest, dass das Startelement unter dem Ansichtsfenster immer noch das Listenelement ist, es sei denn, es bewegt sich weiter nach oben, bis es vollständig außerhalb des Bildschirms liegt.

Der Standard zur Beurteilung des ersten im Ansichtsfenster gerenderten Elements besteht dann darin, dass sich der Scrolltop der Seite zwischen der Oberseite und der Oberseite + Höhe des Listenelementelements befindet.

Basierend auf dem obigen Prinzip kann die binäre Suche verwendet werden, um schnelle Abfragen zu erreichen (Code wie folgt).

// Benutze eine binäre Suche um den Startindex zu berechnen, scrollTop ist die Scrolldistanz getStartIndex (scrollTop) {
      sei Start = 0, Ende = this.list.length – 1;
      während (Start < Ende) {
        const mid = Math.floor((Start + Ende) / 2);
        const { oben, Höhe } = diese.Liste[Mitte];
        wenn (scrollTop >= oben und scrollTop < oben + Höhe) {
          Anfang = Mitte;
          brechen;
        } sonst wenn (scrollTop >= oben + Höhe) {
          Start = Mitte + 1;
        } sonst wenn (scrollTop < oben) {
          Ende = Mitte - 1;
        }
      }
      Rücklaufstart;
}

Die binäre Methode berechnet den Index des ersten Elements, das unter dem Ansichtsfenster im Array this.list gerendert wird und den Namen Startindex start_index trägt. Geben Sie als Nächstes die Kernfunktion getRunData ein (Code wie folgt). Sie führt im Wesentlichen die folgenden beiden Dinge aus.

  • RunList-Listendaten dynamisch aktualisieren
  • Aktualisieren Sie die Position der .list-Langlistenelemente dynamisch

In der tatsächlichen Entwicklung beträgt die maximale Anzahl von Listenelementen (this.maxNum), die der Bildschirm aufnehmen kann, 20, wenn man davon ausgeht, dass die Bildschirmhöhe 1000 Pixel beträgt und das kleinste Listenelement 50 Pixel groß ist.
Berechnen Sie den Startindex start_index basierend auf der Gleitdistanz, und fangen Sie dann basierend auf start_index 20 Elemente aus der Datenquelle this.list ab und weisen Sie sie this.runList zu. Wäre damit nicht die Datenaktualisierung abgeschlossen?

Wenn this.runList nur die maximale Anzahl von Elementen enthält, die auf einen Bildschirm passen, kann die Rendergeschwindigkeit der Benutzeroberfläche beim schnellen Scrollen der Bildlaufleiste nicht mit der Gleitgeschwindigkeit des Fingers mithalten und unten blinkt ein weißer Bildschirm.

Die Lösung für dieses Problem besteht darin, etwas mehr gepufferte Daten im HTML-Dokument darzustellen. Die folgende Funktion getRunData stellt beispielsweise die Anzahl der Listenelemente dar, die für drei Bildschirmhöhen ausreichen, also für den oberen, mittleren und unteren Bildschirm.

Der mittlere Bildschirm ist der Bildschirm, der dem aktuellen Ansichtsfenster entspricht, und der obere und untere Bildschirm speichern die gepufferten Doms, die nicht auf der oberen und unteren Seite des Ansichtsfensters angezeigt werden. Zuerst kann die binäre Suchmethode verwendet werden, um den Index start_index des ersten Listenelementelements unter dem Bildschirmansichtsfenster abzufragen, und dann kann der Index des ersten Listenelements des oberen und unteren Bildschirms auch leicht basierend auf start_index abgerufen werden.

 getRunData(Entfernung = null) {

      //Scroll-Distanz const scrollTop = Distanz? Distanz: this.$refs.container.scrollTop;

      //In welchem ​​Bereich wird nicht gescrollt if (this.scroll_scale) {
        wenn (scrollTop > diese.scroll_scale[0] und scrollTop < diese.scroll_scale[1]) {
          zurückkehren;
        }
      }

      //Startindex let start_index = this.getStartIndex(scrollTop);
      Startindex = Startindex < 0? 0: Startindex;

      //Oberer Bildschirmindex, this.cache_screens ist standardmäßig auf 1 eingestellt, einen Bildschirm zwischenspeichern let upper_start_index = start_index - this.maxNum * this.cache_screens;
      oberer_Startindex = oberer_Startindex < 0? 0: oberer_Startindex;

      // Offset anpassen
      dies.$refs.container.style.transform = `translate3d(0,${this.list[upper_start_index].top}px,0)`;

      //Elemente des mittleren Bildschirms const mid_list = this.list.slice(start_index, start_index + this.maxNum);

      // Oberer Bildschirm const upper_list = this.list.slice(upper_start_index, start_index);

      // Abwärtsbildschirmelement let down_start_index = start_index + this.maxNum;

      down_start_index = down_start_index > diese.Listenlänge - 1 ? diese.Listenlänge : down_start_index;

      this.scroll_scale = [this.list[Math.floor(upper_start_index + this.maxNum / 2)].top, this.list[Math.ceil(start_index + this.maxNum / 2)].top];

      const down_list = diese.list.slice(down_start_index, down_start_index + diese.maxNum * diese.cache_screens);

      this.runList = [...obere_Liste, ...mittlere_Liste, ...untere_Liste];

   }

Das Scroll-Ereignis wird sehr häufig ausgelöst. Als Entwickler müssen wir den Umfang der Browserberechnungen so weit wie möglich reduzieren. Daher kann ein Scroll-Bereich in der Komponente zwischengespeichert werden, d. h. das Array this.scroll_scale (die Datenstruktur ist ähnlich wie [5000,5675]). Wenn die Gleitdistanz innerhalb dieses Bereichs liegt, muss der Browser die Listendaten nicht aktualisieren.

Sobald die Scrolldistanz scrollTop innerhalb des Scrollbereichs liegt, tut die Funktion getRunData nichts. Wenn der Finger gleitet, wird das Standard-Scrollverhalten verwendet, um das .list-Element mit dem Finger nach oben und unten zu bewegen.

Angenommen, die Bildlaufrichtung ist nach unten. Wenn scrollTop den Bildlaufbereich verlässt und die Oberkante des gleitenden viewport.wrapper mit der Oberkante des nächsten Listenelements zusammenfällt, berechnet die Funktion getRunData zuerst den Startindex start_index und ermittelt dann über start_index den Index des ersten Elements im oberen Bildschirmbereich upper_start_index.

Da jedes Listenelement seinen Abstand vom Anfang der langen Liste zwischengespeichert hat, als die Komponente zuvor montiert wurde, können die Positionsinformationen, die dem .list-Element zugewiesen werden sollen, über this.list[upper_start_index].top abgerufen werden. Anschließend wird die neue Listendaten-runList neu berechnet, um die Seite zu rendern, und der Bildlaufbereich im neuen Status wird zwischengespeichert.

Bisher wurde virtuelles Scrollen durch die oben genannten Schritte realisiert. Obwohl die oben vorgestellte praktische Methode sehr einfach anzuwenden ist, müssen Designer beim Planen des Designentwurfs zunächst die Höhe verschiedener Stillistenelemente definieren.

Wenn die Höhe der Listenelemente sich natürlich entsprechend dem Inhalt erweitern muss und beim Entwerfen der Seite nicht festgelegt werden kann, können Sie zum Erreichen dieser Funktion den folgenden Referenzartikel lesen.
Obwohl virtuelles Scrollen mit adaptiver Listenelementhöhe verlockend klingt, erfordert es zusätzliche Verarbeitungsschritte und bringt neue Probleme mit sich (wenn das Listenelement beispielsweise asynchron geladene Bilder enthält, wird die Höhenberechnung schwierig) und erhöht auch den Rechenaufwand für den Browser erheblich. Daher hängt es vom jeweiligen Szenario ab, ob das Listenelement im Design die Höhe definieren muss.

Quellcode

Quellcode

siehe

Hochleistungs-Rendering von 100.000 Datenelementen Eine Implementierungsmethode für virtuelles Scrollen, die selbst Anfänger verstehen können Eine kurze Einführung in das Implementierungsprinzip virtueller Listen

Damit ist dieser Artikel über den Beispielcode zur einfachen Implementierung von virtuellem Scrollen in Vue abgeschlossen. Weitere relevante Inhalte zum virtuellen Scrollen in Vue finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Beispielcode für virtuelle Bildlaufleiste basierend auf vue.js 2.x

<<:  Offlineinstallation von Centos7.2 mysql5.7.18.tar.gz

>>:  So zeigen Sie Serverhardwareinformationen in Linux an

Artikel empfehlen

Detaillierte Analyse der Rolle von HTML-Kommentar-Tags <!--...-->

Wenn wir den Quellcode vieler Websites überprüfen...

js zur Implementierung einer Überprüfungscode-Interferenz (dynamisch)

In diesem Artikelbeispiel wird der spezifische Co...

Implementierung der schnellen Projektkonstruktion von vue3.0+vant3.0

Inhaltsverzeichnis 1. Projektkonstruktion 2. Vue3...

Detaillierte Erklärung der Rolle und des Prinzips des Schlüssels in Vue

Inhaltsverzeichnis 1. Beginnen wir mit dem Fazit ...

Beitrag zur Übermittlung von HTML-Daten_PowerNode Java Academy

Zu den vom HTTP/1.1-Protokoll angegebenen HTTP-An...

Ursachen und Lösungen für Verzögerungen bei der MySQL Master-Slave-Replikation

Inhaltsverzeichnis Ein kurzer Überblick über die ...

Detaillierte Erklärung zur Verwendung des Arguments-Objekts in JavaScript

Inhaltsverzeichnis Vorwort Grundlegende Konzepte ...

jQuery-Plugin zur Implementierung des Suchverlaufs

Jeden Tag ein jQuery-Plugin – um einen Suchverlau...

Informationen zu UDP in Linux

Inhaltsverzeichnis 1. Einführung in UDP und Linux...

So installieren Sie Docker mithilfe von Skripten unter Linux Centos

Was ist die Hauptfunktion von Docker? Derzeit gib...