Ditunda penggunaan fungsi direktif dalam Angular

Baru-baru ini, saya harus menyelesaikan masalah mengubah mekanisme lama untuk menampilkan tooltips, yang diimplementasikan dengan menggunakan pustaka komponen kami, ke yang baru. Seperti biasa, saya memutuskan untuk tidak menciptakan sepeda. Untuk mulai memecahkan masalah ini, saya mulai mencari pustaka sumber terbuka yang ditulis dalam JavaScript murni yang dapat ditempatkan dalam arahan Angular dan digunakan dalam formulir ini. Dalam kasus saya, karena saya sering bekerja dengan popper.js , saya menemukan perpustakaan tippy.js



ditulis oleh pengembang yang sama. Bagi saya, perpustakaan seperti itu tampak seperti solusi sempurna untuk masalah ini. Perpustakaan tippy.js memiliki serangkaian fitur yang luas. Dengan bantuannya, Anda dapat membuat tooltips (elemen tooltip), dan banyak elemen lainnya. Elemen-elemen ini dapat dikustomisasi menggunakan tema, mereka cepat, sangat diketik, menyediakan aksesibilitas ke konten, dan berbeda dalam banyak fitur berguna lainnya.

Saya mulai dengan membuat arahan pembungkus untuk tippy.js:

@Directive({ selector: '[tooltip]' })
export class TooltipDirective {
  private instance: Instance;
  private _content: string;

  get content() {
    return this._content;
  }

  @Input('tooltip') set content(content: string) {
    this._content = content;
    if (this.instance) this.instance.setContent(content);
  }

  constructor(private host: ElementRef<Element>, private zone: NgZone) {}

  ngAfterViewInit() {
    this.zone.runOutsideAngular(() => {
      this.instance = tippy(this.host.nativeElement, {
        content: this.content,
      });
    });
}

Tooltip dibuat dengan memanggil fungsi tippydan elemen lewat hostdan untuk itu content. Selain itu, kami menelepon di tippyluar Zona Angular, karena kami tidak memerlukan peristiwa yang dicatat tippyuntuk memicu siklus deteksi perubahan.

Sekarang kita akan menggunakan tooltip dalam daftar besar 700 elemen:

@Component({
  selector: 'my-app',
  template: `
    <ul>
      <li *ngFor="let item of data" [tooltip]="item.label">
         {{ item.label }}
      </li>
    </ul>
  `
})
export class AppComponent {
  data = Array.from({ length: 700 }, (_, i) => ({
    id: i,
    label: `Value ${i}`,
  }));
}

Semuanya berfungsi seperti yang diharapkan. Setiap item menampilkan tip alat. Tapi kita bisa menyelesaikan masalah ini dengan lebih baik. Dalam kasus kami, 700 salinan telah dibuat tippy. Dan untuk setiap elemen, alat tippy.js menambahkan 4 pendengar acara. Ini berarti bahwa kami mendaftarkan 2800 pendengar (700 * 4).

Untuk melihatnya sendiri, Anda dapat menggunakan metode ini getEventListenersdi konsol Alat Pengembang Chrome. Konstruk tampilan getEventListeners(element)mengembalikan informasi tentang pendengar acara yang terdaftar untuk elemen tertentu.


Ringkasan semua pendengar acara

Jika Anda meninggalkan kode dalam formulir ini, ini dapat memengaruhi konsumsi memori aplikasi dan untuk waktu rendering pertama. Ini terutama berlaku untuk output halaman pada perangkat seluler. Mari kita renungkan ini. Apakah saya perlu membuat instancetippyuntuk item yang tidak ditampilkan di viewport? Tidak, itu tidak perlu.

Kami akan menggunakan APIIntersectionObserveruntuk menunda dimasukkannya dukungan tooltip sampai item muncul di layar. Jika Anda tidak terbiasa dengan APIIntersectionObserver, lihat dokumentasi

Buat untukIntersectionObserverpembungkus yang diwakili oleh objek yang diamati:

const hasSupport = 'IntersectionObserver' in window;

export function inView(
  element: Element,
  options: IntersectionObserverInit = {
    root: null,
    threshold: 0.5,
  }
) {
  return new Observable((subscriber) => {
    if (!hasSupport) {
      subscriber.next(true);
      subscriber.complete();
    }

    const observer = new IntersectionObserver(([entry]) => {
      subscriber.next(entry.isIntersecting);
    }, options);

    observer.observe(element);

    return () => observer.disconnect();
  });
}

Kami menciptakan objek yang dapat diamati yang menginformasikan pelanggan tentang saat elemen tersebut bersinggungan dengan area tertentu. Selain itu, di sini kami memeriksa dukungan IntersectionObserverbrowser. Jika browser tidak mendukung IntersectionObserver, kami cukup mengeluarkan truedan keluar. Pengguna IE sendiri yang harus disalahkan atas kesengsaraan mereka.

Sekarang inViewkita bisa menggunakan objek yang diamati dalam arahan yang mengimplementasikan fungsionalitas tooltip:

@Directive({ selector: '[tooltip]' })
export class TooltipDirective {
  ...

  ngAfterViewInit() {
    //   
    inView(this.host.nativeElement).subscribe((inView) => {
      if (inView && !this.instance) {
        this.zone.runOutsideAngular(() => {
          this.instance = tippy(this.host.nativeElement, {
            content: this.content,
          });
        });
      } else if (this.instance) {
        this.instance.destroy();
        this.instance = null;
      }
    });
  }
}

Jalankan kode lagi untuk menganalisis jumlah pendengar acara.


Ringkasan semua pendengar acara setelah penyelesaian proyek

Unggul. Sekarang kita membuat tooltips hanya untuk elemen yang terlihat.

Mari kita mencari jawaban untuk beberapa pertanyaan yang berkaitan dengan solusi baru.

Mengapa kita tidak menggunakan pengguliran virtual untuk menyelesaikan masalah ini? Pengguliran virtual tidak dapat digunakan dalam situasi apa pun. Dan, di samping itu, pustaka Bahan Sudut menyimpan templat, sebagai hasilnya, data yang sesuai akan terus menempati memori.

Bagaimana dengan delegasi acara? Untuk melakukan ini, Anda perlu menerapkan mekanisme tambahan sendiri, di Angular tidak ada cara universal untuk menyelesaikan masalah ini.

Ringkasan


Di sini kita berbicara tentang bagaimana menunda penerapan fungsi arahan. Ini memungkinkan aplikasi memuat lebih cepat dan mengonsumsi lebih sedikit memori. Contoh tooltip hanyalah salah satu dari banyak kasus di mana teknik serupa dapat diterapkan. Saya yakin Anda akan menemukan banyak cara untuk menggunakannya dalam proyek Anda sendiri.

Dan bagaimana Anda memecahkan masalah menampilkan daftar besar elemen, yang masing-masing perlu dilengkapi dengan tooltip?

Kami mengingatkan Anda bahwa kami melanjutkan kontes prediksi di mana Anda dapat memenangkan iPhone baru. Masih ada waktu untuk menerobosnya, dan membuat perkiraan paling akurat tentang nilai-nilai topikal.


All Articles