• Czas czytania ~5 min
  • 14.03.2023

W tym samouczku zaimplementujemy Livewire Infinite Scrolling, który automatycznie załaduje rekordy z bazy danych, gdy użytkownik przewinie do dołu listy. W przeciwieństwie do innych przykładów, które mogłeś zobaczyć, upewnimy się, że nasz kod jest wydajny i nie pobiera wszystkich rekordów podczas ponownego renderowania komponentu.

Preview

Zaczynam od Fresh Laravel Project z zainstalowanym Livewire. Zainstalowałem również Breeze, ale nie jest to obowiązkowe i całkowicie zależy od ciebie. Ustawiłem również trasę, na której będziemy wyświetlać nasz komponent Livewire. I wreszcie, mam Model Produktu, który zasiałem kilkoma rekordami. Będziemy przewijać listę Produktów.

Możemy utworzyć komponent Livewire za pomocą poniższego polecenia Artisan.

php artisan make:livewire LoadProducts

Możemy wyrenderować go w naszym widoku za pomocą poniższego polecenia

@livewire('load-products')

W ramach tego komponentu Livewire zdefiniuję 2 właściwości $page i $perPage. Zamierzam ustawić te właściwości w metodzie mount.

<?php

namespace App\Http\Livewire;

use App\Models\Product;
use Livewire\Component;

class LoadProducts extends Component
{
    public $perPage;
    public $page;

    public function mount($page = null, $perPage = null) 
    {
        $this->page = $page ?? 1;
        $this->perPage = $perPage ?? 10;
    }
}

Ponieważ nie podaliśmy żadnych wartości podczas renderowania komponentu $page Livewire i będziemy mieli wartość domyślną odpowiednio 1 i $perPage 10.

Następnie utworzymy metodę renderowania, która zwróci rekordy odpowiadające 1st Page i przekaże ją do naszego View load-products

public function render()
    {
        $products = Product::paginate($this->perPage, ['*'], null, $this->page);
        return view('livewire.products.load-products', [
            'products' => $products
        ]);
    }

W naszym pliku widoku, który znajduje się pod adresem resources/views/livewire/products/load-products.blade.php , możemy po prostu zapętlić wszystkie produkty.

<div>
    @foreach($productsas $result)
       .
       . 
       .
    @endforeach
</div>

Na tym etapie, jeśli otworzysz trasę zawierającą ten komponent Livewire, zobaczysz pierwszych 10 rekordów.

Przede wszystkim użyjemy przycisku do załadowania większej liczby rekordów. Gdy to zadziała, przełączymy się na przewijanie.

Teraz możemy dodać przycisk po zakończeniu naszej foreach pętli, jak poniżej

<x-button wire:click="loadMore">Load More Products</x-button>

Po kliknięciu tego przycisku musimy pobrać kolejne 10 rekordów i dołączyć do bieżącej listy. Jednak Livewire renderuje cały komponent, dzięki czemu możemy użyć podejścia dołączania.

Drugą opcją jest pobranie wszystkich 20 rekordów i ponowne wyrenderowanie komponentu. Da to iluzję ładowania większej ilości danych, ale ma poważne problemy z wydajnością.

Zamiast tego zamierzamy stworzyć kolejny komponent, LoadMoreProducts. Ten komponent byłby odpowiedzialny za:

  1. Wyświetlanie powyższego przycisku Załaduj więcej produktów.
  2. Obsługa zdarzenia kliknięcia, które spowoduje pobranie Produktów na 2. i kolejne strony.
  3. Warunkowe wyświetlanie widoku związanego z LoadProducts Składnik.

Możemy więc utworzyć ten komponent za pomocą poniższego polecenia:

php artisan make:livewire LoadMoreProducts

Dodamy ten komponent w naszym pliku widoku na resources/views/livewire/products/load-products.blade.php przykład poniżej:

@if($products->hasMorePages())
        @livewire('load-more-products', ['page' => $page, 'perPage' => $perPage, 'key' => 'products-page-' . $page])
    @endif

Prosimy o zapoznanie się z tym, że wyświetlamy ten Komponent tylko wtedy, gdy do pobrania jest więcej Produktów. Mijamy $page $perPage również i Nieruchomość. Używamy również unikalnego klucza, aby go zidentyfikować, ponieważ będzie wiele tych komponentów, 1 dla każdej następnej strony.

W naszym pliku komponentu znajdującym się pod adresem app/Http/Livewire/LoadMoreProducts, będziemy mieli następujący kod, który na tym etapie jest bardzo podobny do LoadProducts

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Product;

class LoadMoreProducts extends Component
{

    public $perPage;
    public $page;
    public $loadMore = false;

    public function mount($page = null, $perPage = null) 
    {
        $this->page = $page ?? 1;
        $this->perPage = $perPage ?? 10;
    }

    public function render()
    {
        return view('livewire.products.load-more-products');
    }
}

W pliku widoku tego komponentu znajdującym się pod adresem resources/views/livewire/products/load-more-products.blade.php, ostatecznie wyświetlimy nasz przycisk.

<x-button wire:click="loadMore">Load More Products</x-button>

Jak widać, wywołujemy loadMore metodę za jednym kliknięciem tego przycisku. Musimy zdefiniować tę metodę w LoadMoreProducts komponencie i będzie ona obsługiwać następujące funkcjonalności:

  1. Będziemy zwiększać $page Właściwość o 1.
  2. Zdefiniujemy nową flagę loadMore i ustawimy ją na true.
  3. W ramach metody renderowania sprawdzimy powyższą flagę. Jeśli ta flaga jest prawdziwa, pobierzemy rekordy z bazy danych dla danego $page i wyświetlimy widok związany z LoadProducts komponentem. W przeciwnym razie wyświetlimy tylko widok Związany z LoadMoreProducts, który renderuje przycisk.

Oto jak wygląda nasz komponent LoadMoreProducts

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Product;

class LoadMoreProducts extends Component
{

    public $perPage;
    public $page;
    public $loadMore = false;

    public function mount($page = null, $perPage = null) 
    {
        $this->page = $page ?? 1;
        $this->perPage = $perPage ?? 10;
    }

    public function loadMore() 
    {
        $this->page += 1;
        $this->loadMore = true;
    }

    public function render()
    {
        if (!$this->loadMore) {
            return view('livewire.products.load-more-products');
        } else {
            $products = Product::paginate($this->perPage, ['*'], null, $this->page);

            return view('livewire.products.load-products', [
                'products' => $products
            ]);
        }
    }
}

Tak więc, gdy Użytkownik prosi o 2nd Page, pobieramy Produkty związane z 2nd Page i wyświetlamy je za pośrednictwem livewire.products.load-products. Ten widok wyświetla również przycisk "Załaduj więcej produktów" dla strony 3rd.

W ten sposób, rozbijając funkcjonalność na dwa komponenty, rozwiązaliśmy problem dołączania do aktualnej listy.

Teraz wprowadźmy zmiany, aby załadować więcej produktów podczas przewijania użytkownika, a nie kliknięcia przycisku. Musimy tylko wprowadzić zmiany w widoku LoadMoreProducts. Musimy uruchomić zdarzenie kliknięcia, gdy użytkownik przewinie do końca listy. Możemy to zrobić, korzystając z x-init dyrektywy AlpineJs.

<div x-data="{
    checkScroll() {
            window.onscroll = function(ev) {
                if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
                     @this.call('loadMore')
                }
            };
        }
    }"

    x-init="checkScroll"
>

Teraz, gdy użytkownik przewinie do końca listy, metoda zostanie uruchomiona, loadMore a rekordy zostaną dołączone na końcu listy. Otrzymamy takie same dane wyjściowe, jak pokazano na obrazku na początku samouczka.

Jeśli jesteś zainteresowany kodem, możesz go pobrać z Github.

Mam nadzieję, że podobał Ci się ten samouczek. W przypadku podobnych artykułów możesz śledzić mnie na Twitterze

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297