1. Hintergrund Während des Entwicklungsprozesses stoßen wir immer wieder auf die Anzeige vieler Listen. Wenn Listen dieser Größenordnung im Browser gerendert werden, führt dies letztendlich zu einer Verschlechterung der Browserleistung. Ist die Datenmenge zu groß, wird erstens das Rendering extrem langsam und zweitens bleibt die Seite direkt hängen. Natürlich können Sie auch andere Wege wählen, um dies zu vermeiden. Beispielsweise Paging oder Herunterladen von Dateien und so weiter. Hier besprechen wir, wie dieses Problem mithilfe virtueller Listen gelöst werden kann. 2. Was ist eine virtuelle ListeDie einfachste Beschreibung: Wenn die Liste scrollt, ändern Sie die Rendering-Elemente im sichtbaren Bereich. Die [Gesamthöhe der Liste] und die [Höhe des Visualisierungsbereichs] werden durch die [geschätzte Höhe eines einzelnen Datenelements] berechnet. Und rendern Sie die Liste nach Bedarf innerhalb von [Höhe des Visualisierungsbereichs]. 3. Einführung in verwandte KonzepteIm Folgenden werden einige sehr wichtige Parameterinformationen in der Komponente vorgestellt. Lassen Sie uns diese hier zunächst verstehen, um einen Eindruck zu bekommen, damit sie bei späterer Verwendung klarer sind.
4. Implementierung virtueller ListenDie virtuelle Liste kann einfach so verstanden werden: Wenn die Liste gescrollt wird, werden die Rendering-Elemente innerhalb der [Höhe des Visualisierungsbereichs] geändert. Gemäß den oben eingeführten relevanten Konzepten befolgen wir diese Schritte basierend auf diesen Eigenschaften:
Beginnen wir gemäß den obigen Einführungsschritten mit der Implementierung einer virtuellen Liste. 4.1 Treiberentwicklung: Parameteranalyse
4.1.1 Artikel rendern importiere React, { useState } von 'react'; importiere { VirtualList } aus „biz-web-library“; // Definieren Sie die Komponente für die Anzeige der einzelnen Daten const ItemRender = ({ data }) => { let dindex = parseInt(Daten); lass lineHeight = dindex % 2 ? '40px' : '80px'; zurückkehren ( <div Stil = {{ Zeilenhöhe, Hintergrund: dindex % 2 ? '#f5f5f5' : '#fff' }}> <h3>#{dindex} Titelname</h3> <p>Schreiben Sie, was Sie wollen, keine Begrenzung der Seitenhöhe</p> </div> ); }; const ItemRenderMemo = React.memo(ItemRender); 4.1.2 Initialisierung der Datenliste // Listendaten initialisieren const getDatas = () => { const Daten = []; für (sei i = 0; i < 100000; i++) { datas.push(`${i} Element`); } Daten zurückgeben; }; 4.1.3 Verwendung // Virtuelle Liste verwenden export default () => { let [Ressourcen, setResources] = useState([]); const changeResources = () => { : Setze Ressourcen(getDatas()); }; zurückkehren ( <div> <button onClick={changeResources}>klick mich </button> <div Stil={{ Höhe: '400px', Überlauf: „auto“, Rahmen: '1px durchgezogen #f5f5f5', Polsterung: '0 10px', }} > <VirtuelleListe ItemRender={ItemRenderMemo} Ressourcen={Ressourcen} geschätzteArtikelgröße={60} /> </div> </div> ); }; 4.2 Berechnung und Layout der KomponenteninitialisierungNachdem wir nun wissen, wie man es verwendet, beginnen wir mit der Implementierung unserer Komponente. Berechnen Sie die Initialisierungsposition jedes Datenelements basierend auf den in der Datenquelle übergebenen Ressourcen und der geschätzten Höhe ( EstimatedItemSize). // Gesamtinitialisierungshöhe der Ringcacheliste export const initPositinoCache = ( geschätzteArtikelgröße: Zahl = 32, Länge: Zahl = 0, ) => { sei Index = 0, Positionen = Array(Länge); während (Index < Länge) { Positionen[Index] = { Index, Höhe: geschätzteArtikelgröße, oben: Index * geschätzteArtikelgröße, unten: (Index++ + 1) * geschätzteArtikelgröße, }; } Positionen zurückgeben; }; Wenn die Höhe aller Daten in der Liste konsistent ist, ändert sich diese Höhe nicht. Wenn die Höhe der einzelnen Daten nicht festgelegt ist, wird die Position während des Bildlaufvorgangs aktualisiert. Hier sind einige andere Parameter, die initialisiert werden müssen:
Tatsächlich ist die Bedeutung jedes Attributs nach einer kurzen Einführung klar zu erkennen. Der Parameter [startOffset] muss jedoch ausführlich eingeführt werden. Es handelt sich um eine wichtige Eigenschaft, die während des Scrollvorgangs ein unendliches Scrollen simuliert. Sein Wert gibt die Position von oben während unseres Scrollvorgangs an. [startOffset] erreicht den Effekt des unendlichen Scrollens durch die Kombination von [visibleData]. // Zwischenspeichern Sie die Positionen aller Elemente let positions: Array<PositionType>; Klasse VirtualList erweitert React.PureComponent{ Konstruktor(Requisiten) { super(Requisiten); const { Ressourcen } = this.props; // Cache-Positionen initialisieren = initPositinoCache(props.estimatedItemSize, resources.length); dieser.Zustand = { Ressourcen, StartOffset: 0, listHeight: getListHeight(positions), // unteres Attribut der letzten Daten in Positionen scrollRef: React.createRef(), // virtueller Listencontainer ref Elemente: React.createRef(), // Virtueller Listenanzeigebereich ref visibleCount: 10, // Anzahl der sichtbaren Bereiche auf einer Seite startIndex: 0, // Startindex des sichtbaren Bereichs endIndex: 10, // // Endindex des sichtbaren Bereichs }; } // TODO: Einige andere Funktionen ausblenden. . . . . //Layout rendern() { const { ItemRender = ItemRenderComponent, Erweiterung } = this.props; const { Listenhöhe, Startoffset, Ressourcen, Startindex, Endindex, Elemente, Scrollreferenz } = dieser.Zustand; let visibleData = resources.slice(startIndex, endIndex); zurückkehren ( <div ref={scrollRef} Stil={{ Höhe: `${listHeight}px` }}> <ul ref={Artikel} Stil={{ transformieren: `translate3d(0,${startOffset}px,0)`, }} > {visibleData.map((Daten, Index) => { zurückkehren ( <li Schlüssel={Daten.ID || Daten.Schlüssel || Index} Datenindex={`${startIndex + index}`}> <ItemRender-Daten = {Daten} {...extrea}/> </li> ); })} </ul> </div> ); } } 4.3 Scrollen löst Registrierungsereignisse und Aktualisierungen ausRegistrieren Sie onScroll über [componentDidMount] im DOM. Beim Scroll-Ereignis wird requestAnimationFrame verwendet. Diese Methode nutzt die Leerlaufzeit des Browsers zur Ausführung, was die Leistung des Codes verbessern kann. Wenn Sie ein tieferes Verständnis wünschen, können Sie sich die spezifische Verwendung dieser API ansehen. componentDidMount() { Ereignisse.auf(dieses.getEl(), 'scroll', dieses.aufScrollen, falsch); events.on(this.getEl(), 'Mausrad', NOOP, false); // Berechnen Sie den neuesten Knoten basierend auf dem Rendering let visibleCount = Math.ceil(this.getEl().offsetHeight / estimateItemSize); wenn (sichtbarerAnzahl === dieser.Zustand.sichtbarerAnzahl || sichtbarerAnzahl === 0) { zurückkehren; } // Aktualisiere endIndex, listHeight/offset, da visibleCount sich geändert hat this.updateState({ visibleCount, startIndex: this.state.startIndex }); } getEl = () => { let el = dieser.Zustand.scrollRef || dieser.Zustand.Elemente; let parentEl: any = el.current?.parentElement; Schalter (Fenster.getComputedStyle(parentEl)?.overflowY) { Fall 'auto': Fall 'scrollen': Fall 'Overlay': Fall 'sichtbar': returniere übergeordnetesEl; } Dokumenttext zurückgeben; }; beimScrollen = () => { requestAnimationFrame(() => { let { scrollTop } = this.getEl(); let startIndex = binarySearch(positionen, scrollTop); // Da sich der Startindex ändert, aktualisiere den Endindex und die Listenhöhe/den Offset. this.updateState({ visibleCount: this.state.visibleCount, startIndex}); }); }; Als nächstes analysieren wir die wichtigsten Schritte. Beim Scrollen können wir den [scrollTop] des aktuellen virtuellen Listencontainers [scrollRef] abrufen. Über diese Distanz und [Positionen] (die alle Positionseigenschaften jedes Elements aufzeichnen) können wir den Startindex dieser Position abrufen. Um die Leistung zu verbessern, verwenden wir die binäre Suche: // Tool-Funktion, in Tool-Datei einfügen export const binarySearch = (list: Array<PositionType>, value: number = 0) => { lass starten: Zahl = 0; let end: Zahl = Listenlänge – 1; lass tempIndex = null; während (Start <= Ende) { let midIndex = Math.floor((start + end) / 2); sei mittlererWert = Liste[mittlererIndex].unten; // Wenn die Werte gleich sind, wird der gefundene Knoten direkt zurückgegeben (da dieser unten liegt, sollte startIndex der nächste Knoten sein) wenn (Mittelwert === Wert) { gibt MidIndex + 1 zurück; } // Wenn der mittlere Wert kleiner als der Eingabewert ist, bedeutet das, dass der dem Wert entsprechende Knoten größer als Start ist, und Start wird um eine Position zurückbewegt, sonst wenn (Mittelwert < Wert) { Start = Mittelindex + 1; } // Wenn der mittlere Wert größer als der Eingabewert ist, bedeutet dies, dass der Wert vor dem mittleren Wert liegt und der Endknoten zur Mitte - 1 verschoben wird. sonst wenn (Mittelwert > Wert) { // tempIndex speichert alle Werte, die dem Wert am nächsten sind, wenn (tempIndex === null || tempIndex > midIndex) { tempIndex = mittlererIndex; } Ende = mittlererIndex - 1; } } gibt TempIndex zurück; }; Sobald wir den Startindex erhalten haben, aktualisieren wir die Werte aller Eigenschaften im Komponentenstatus basierend auf dem Startindex. updateState = ({ sichtbareAnzahl, startIndex }) => { // Daten entsprechend dem neu berechneten Knoten aktualisieren this.setState({ startOffset: startIndex >= 1 ? Positionen[startIndex - 1]?.unten : 0, Listenhöhe: getListHeight(Positionen), StartIndex, sichtbareAnzahl, endIndex: getEndIndex(diese.state.resources, startIndex, sichtbareAnzahl) }); }; // Das Folgende ist eine Tool-Funktion, die in anderen Dateien abgelegt wird. export const getListHeight = (positions: Array<PositionType>) => { let index = Positionen.Länge - 1; Rückgabeindex < 0? 0: Positionen[Index].unten; }; exportiere const getEndIndex = ( Ressourcen: Array<Daten>, startIndex: Zahl, sichtbareAnzahl: Zahl, ) => { let resourcesLength = Ressourcen.Länge; let endIndex = startIndex + sichtbareAnzahl; Gibt „Ressourcenlänge“ > 0 zurück? Math.min(Ressourcenlänge, Endindex) : Endindex; } 4.4 Aktualisieren Sie die Artikelhöhen, wenn sie nicht gleich sind An diesem Punkt haben wir das grundlegende DOM-Scrollen, die Datenaktualisierung und andere Logik abgeschlossen. Stellen Sie beim Testen jedoch fest, dass die Position und andere Vorgänge nicht aktualisiert wurden, wenn die Höhe nicht gleich ist? Wohin damit? KomponenteDidUpdate() { dies.updateHeight(); } updateHöhe = () => { let-Elemente: HTMLCollection = this.state.items.current?.children; wenn (!items.length) return; // Cache aktualisieren updateItemSize(positions, items); // Gesamthöhe aktualisieren let listHeight = getListHeight(positions); // Gesamten Offset aktualisieren let startOffset = getStartOffset(this.state.startIndex, positions); dies.setState({ Listenhöhe, StartOffset, }); }; // Das Folgende ist eine Tool-Funktion, die in anderen Dateien abgelegt wird export const updateItemSize = ( Positionen: Array<PositionType>, Elemente: HTMLCollection, ) => { Array.von(Elemente).fürJedes(Element => { let index = Zahl(item.getAttribute('Datenindex')); let { Höhe } = item.getBoundingClientRect(); lass alteHeight = Positionen[Index].Höhe; //Wenn ein Unterschied besteht, aktualisiere alle Knoten nach diesem Knoten. let dValue = oldHeight - height; wenn (dWert) { Positionen[Index].unten = Positionen[Index].unten - dWert; Positionen[Index].Höhe = Höhe; für (let k = Index + 1; k < Positionen.Länge; k++) { Positionen[k].oben = Positionen[k - 1].unten; Positionen[k].unten = Positionen[k].unten - dWert; } } }); }; //Den aktuellen Offset abrufen export const getStartOffset = ( startIndex: Zahl, Positionen: Array<PositionType> = [], ) => { startIndex >= 1 zurückgeben? Positionen[startIndex - 1]?.unten: 0; }; export const getListHeight = (positions: Array<PositionType>) => { let index = Positionen.Länge - 1; Rückgabeindex < 0? 0: Positionen[Index].unten; }; 4.5 Externe Parameterdatenänderungen, Komponentendatenaktualisierungen Wenn sich die von uns übergebene externe Datenquelle geändert hat, müssen wir in diesem letzten Schritt die Daten synchronisieren. Dieser Vorgang wird natürlich in der Methode getDerivedStateFromProps abgeschlossen. statisch getDerivedStateFromProps( nextProps: VirtualListProps, vorherigerZustand: VirtualListState, ) { const { Ressourcen, geschätzteArtikelgröße } = nextProps; wenn (Ressourcen !== vorherigerStatus.Ressourcen) { Positionen = initPositinoCache(geschätzteArtikelgröße, Ressourcen.Länge); // Höhe aktualisieren let listHeight = getListHeight(positions); // Gesamten Offset aktualisieren let startOffset = getStartOffset(prevState.startIndex, positions); let endIndex = getEndIndex(Ressourcen, vorherigerZustand.startIndex, vorherigerZustand.visibleCount); zurückkehren { Ressourcen, Listenhöhe, StartOffset, EndeIndex, }; } gibt null zurück; } 5 Fazit OK, eine vollständige virtuelle Listenkomponente ist fertig. Da die Renderfunktion jedes Datenelements angepasst ist, können Sie praktisch jedes Element scrollen, solange es in Listenform vorliegt. Natürlich kann nach den Informationen, die ich online gelesen habe, aufgrund von Netzwerkproblemen beim Scrollen der Bilder nicht die tatsächliche Höhe der Listenelemente garantiert werden, was zu Ungenauigkeiten führen kann. Darauf gehen wir hier vorerst nicht näher ein, Interessierte können gerne tiefer in die Materie einsteigen. Dies ist das Ende dieses Artikels über die Implementierung der virtuellen React-Liste. Weitere relevante Inhalte zur virtuellen React-Liste finden Sie in den vorherigen Artikeln von 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:
|
<<: Grafisches Tutorial zur Installation und Konfiguration von MySQL 8.0.12 (Windows 10)
Inhaltsverzeichnis 1. Grundlagen 2. Knoten, Bäume...
Vorwort Im Internet gibt es häufig Artikel, die v...
1.1 Einführung in die iptables-Firewall Netfilter...
Inhaltsverzeichnis 1. Neue Verwendung der Uhr 1.1...
Lassen Sie uns, ohne ins Detail zu gehen, direkt ...
Farbkontrast und Harmonie Unter kontrastierenden ...
Inhaltsverzeichnis Grundlegende Selektoren: Ebene...
1. Registrieren Sie zunächst Ihr eigenes Dockerhu...
Inhaltsverzeichnis Zugehörige Abhängigkeitsinstal...
Verwenden Sie Textausrichtung, Rand: 0 automatisc...
Moores Gesetz gilt nicht mehr Seit der Übernahme ...
DOMContentLoaded-Ereignis Es wird buchstäblich au...
Seite: Basis: <Vorlage> <div Klasse=&quo...
Dieser Artikel veranschaulicht anhand von Beispie...
Inhaltsverzeichnis Der Unterschied zwischen Hash ...