La risposta breve e dolce è "non iterare sull'intero array", ma non è stato abbastanza buono per me. Volevo che assomigliasse all'intera colonna di voci presenti. Quindi metto un distanziale sopra, il ngPer scorre su una sottosezione dell'array, e uno spaziatore sotto e insieme questo fa apparire la lista come tutti gli elementi ci sono sempre.
Ecco una versione semplificata del mio html con solo le parti relative a questo problema (full example on bitbucket):
<div (scroll)="ColScroll($event)">
<div [style.height]="Math.max(0, Math.max(0, scrollPos - 10) * 132)"></div>
<entry *ngFor="let p of (base.pokemon | filter:search:SelectedVer:SelectedLang) | justafew:scrollPos" [pokemon]="p"></entry>
<div [style.height]="Math.max(0,((base.pokemon | filter:search:SelectedVer:SelectedLang).length - scrollPos - 40)) * 132"></div>
</div>
struttura ultra-minimale per assoluta chiarezza:
<div> <!-- column -->
<div></div> <!-- spacer -->
<entry *ngFor='...'></entry>
<div></div> <!-- spacer -->
</div>
In primo luogo, una chiave point: <entry>
è sempre esattamente 120 pixel di altezza con un margine inferiore di 12 pixel per un totale di 132 pixel di spazio totale. Il CSS lo rende assoluto. Questo funziona per qualsiasi dimensione costante volessi selezionare, ma faccio ipotesi speciali che la dimensione sia esattamente di 132 pixel.
La versione breve è che quando si scorre, scrollHeight della colonna determina quali voci dovrebbero effettivamente essere sullo schermo. Se i primi 10 elementi creati da ngFor sono fuori dallo schermo, il primo elemento visibile inizia dal numero 11. Conto per uno schermo a 4k e visualizzo 40 voci (occupando 5280 pixel) per essere sicuro che l'intera colonna sia piena. Quindi, in modo che la barra di scorrimento appaia corretta, ho un distanziale sotto le 40 voci per forzare il div a avere l'altezza scorrevole adatta.Ecco un'immagine di quello che sta visivamente succedendo:
Ecco le variabili e le funzioni pertinenti del controllore (bitbucket):
scrollPos = 0;
...
ColScroll(event: Event) {
let pos = $(event.target).scrollTop();
this.scrollPos = Math.floor(pos/132);
}
uccide me di utilizzare jQuery qui, ma ero già usando per qualcos'altro e avevo bisogno di qualcosa di cross-browser. scrollPos
contiene il primo indice del primo elemento che dovrei mostrare sullo schermo.
Il ngFor che costruisce effettivamente tutti gli elementi <entry>
assomiglia a questo:
*ngFor="let p of (base.pokemon | filter:search:SelectedVer:SelectedLang) | justafew:scrollPos"
rottura che giù:
base.pokemon
è un array di dati pokemon necessari per creare ciascun elemento d'accesso.
... | filter:search:SelectedVer:SelectedLang)
viene utilizzato per la ricerca nell'elenco. Lascio il mio esempio qui per dimostrare che è ancora possibile giocare con la lista prima che il mio hack entri in gioco.
... | justafew:scrollPos
è dove la magia accade. Ecco che il filtro nella sua interezza (bitbucket):
import { Pipe, PipeTransform } from '@angular/core';
import { MinPokemon } from '../models/base';
@Pipe({
name: 'justafew',
pure: false
})
export class JustAFewPipe implements PipeTransform {
public transform(value: MinPokemon[], start: number): MinPokemon[] {
return value.slice(Math.max(0, start - 10), start + 30);
}
}
scrollPos
è stata approvata nel come parametro start
. Ad esempio, se ho spostato i miei 13200 pixel verso il basso nella colonna, scrollPos
è impostato su 100 (vedere l'evento di scorrimento nel controller in alto). Questo troncerà la matrice in modo che restituisca gli elementi da 90 a 130. Voglio un po 'esagerare lo schermo per garantire che lo scorrimento veloce non provochi uno spazio bianco visibile (lo scorrimento follemente veloce potrebbe ancora mostrarlo ma ti stai muovendo così velocemente è facile pensare che il browser non sia stato reso così veloce, quindi lo lascio scorrere). Io uso Math.max
quindi non affondo utilizzando numeri negativi come quando sono in cima alla lista e scrollPos
è 0.
Ora i distanziali. Mantengono la barra di scorrimento onesta. Lego il loro [style.height]
e uso un po 'di matematica per fare in modo che questi distanziatori occupino lo spazio richiesto. Mentre scorro verso il basso, il distanziale superiore diventa più alto e il distanziatore inferiore si restringe esattamente dello stesso valore in modo che la colonna abbia sempre la stessa altezza. Quando eseguo il backup, la matematica risolve esattamente il contrario: la parte superiore si restringe e il fondo cresce. Lo spacer bottom utilizza la stessa logica del filtro di ngFor in modo tale che se eseguo una ricerca che restituisce 100 anziché 721 pokemon, si adatta all'altezza di 100 voci. Il primo distanziale utilizza scrollPos - 10
perché il filtro justafew
torna indietro 10. Per lo stesso motivo, lo spaziatore di fondo utilizza scrollPos - 30
perché è il numero di justafew
restituito.
So che sembra un sacco di parti mobili ma sono tutte semplici e veloci. Sfortunatamente ci sono molti "numeri magici" in tutto il luogo che si fidano l'uno dell'altro ma considerando i miglioramenti e l'affidabilità delle prestazioni questo mi ha dato la possibilità di mostrare l'intera lista che ho lasciato scorrere. Forse un giorno farò un componente o una direttiva per mettere tutto in un posto configurabile.
Non sono sicuro di come si visualizzano i dati, ma non è necessario mostrare 721 elementi sullo schermo. Sarai solo in grado di vederne una frazione. Non puoi semplicemente sfogliare i dati in modo che sia più facile guardarli? Quindi mostreresti solo 10 - 100 pokemon anziché 721. Ciò renderebbe molto più veloce. – DerekMT12
e [questo] (https: //www.npmjs.com/package/angular2-infinito-scroll) dovrebbe aiutarti con l'impaginazione – FernOfTheAndes
La migliore ottimizzazione è non fare nulla. Come già detto, rende solo ciò che deve essere visualizzato in una sola volta. –