• Время чтения ~2 мин
  • 14.03.2023

В этом уроке мы реализуем Livewire Infinite Scrolling, которая автоматически загружает записи из базы данных по мере прокрутки пользователя в нижнюю часть списка. И в отличие от других примеров, которые вы, возможно, видели, мы позаботимся о том, чтобы наш код был производительным и не извлекал все записи при повторном рендеринге компонента.

Preview

Я начинаю с проекта Fresh Laravel с установленным Livewire. Я также установил Breeze, но это не обязательно и полностью зависит от вас. Я также настроил Route, где мы собираемся отобразить наш компонент Livewire. И, наконец, у меня есть модель продукта, которую я засеял несколькими записями. Мы будем прокручивать список Продуктов.

Мы можем создать компонент Livewire, используя приведенную ниже команду Artisan.

php artisan make:livewire LoadProducts

Мы можем отобразить его в нашем представлении, используя следующую команду

@livewire('load-products')

И в этом компоненте Livewire я собираюсь определить 2 свойства, $page и $perPage. Я собираюсь установить эти свойства в методе 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;
    }
}

Так как мы не предоставили никаких значений при рендеринге компонента Livewire, $page и $perPage будем иметь значение по умолчанию 1 и 10 соответственно.

Далее мы создадим метод рендеринга, который вернет записи, соответствующие 1-й странице, и передаст их в наш вид load-products

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

В нашем файле View, который находится по адресу resources/views/livewire/products/load-products.blade.php , мы можем просто перебрать все продукты.

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

На этом этапе, если вы откроете свой маршрут, содержащий этот компонент Livewire, вы увидите первые 10 записей.

Прежде всего, мы собираемся использовать кнопку для загрузки большего количества записей. Как только мы заставим это работать, мы переключимся на прокрутку.

Теперь мы можем добавить кнопку после того, как наш foreach цикл закончится, как показано ниже

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

Одним нажатием этой кнопки нам нужно получить следующие 10 записей и добавить к текущему списку. Тем не менее, Livewire отображает весь компонент, поэтому мы можем использовать подход добавления.

Второй вариант — получить все 20 записей и снова отобразить компонент. Это даст иллюзию загрузки дополнительных данных, но у него есть серьезные проблемы с производительностью.

Вместо этого мы собираемся создать еще один компонент, LoadMoreProducts. Этот компонент будет отвечать за:

  1. Отображение приведенной выше кнопки Загрузить больше продуктов.
  2. Обработка события Click, которое принесет Продукты для 2-й и последующих Страниц.
  3. Условное отображение представления, связанного LoadProducts с Компонент.

Таким образом, мы можем создать этот компонент, используя следующую команду:

php artisan make:livewire LoadMoreProducts

Мы добавим этот компонент в наш файл просмотра, как показано resources/views/livewire/products/load-products.blade.php ниже:

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

Пожалуйста, убедитесь, что мы показываем этот компонент только в том случае, если есть больше Продуктов, которые необходимо получить. Мы также передаем $page и $perPage Собственность. Мы также используем уникальный ключ для его идентификации, так как этих компонентов будет несколько, по 1 для каждой последующей страницы.

В нашем файле компонентов, расположенном по адресу app/Http/Livewire/LoadMoreProducts, у нас будет следующий код, который на данном этапе очень похож на 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');
    }
}

В файле просмотра этого компонента, расположенном по адресу resources/views/livewire/products/load-more-products.blade.php, мы в конечном итоге отобразим нашу кнопку.

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

Как видите, мы вызываем loadMore метод одним нажатием этой кнопки. Нам нужно определить этот метод в LoadMoreProducts Component, и он будет обрабатывать следующие функциональные возможности:

  1. Мы увеличим $page свойство на 1.
  2. Мы определим новый флаг loadMore и установим для него значение true.
  3. В методе рендеринга мы проверим вышеуказанный флаг. Если этот флаг имеет значение true, мы извлекем записи из базы данных для заданного $page и отобразим представление, связанное с LoadProducts компонентом. В противном случае мы просто отобразим View Related to LoadMoreProducts, который отображает кнопку.

Вот как выглядит наш компонент 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
            ]);
        }
    }
}

Поэтому, когда Пользователь запрашивает 2-ю Страницу, мы получаем Продукты, связанные со 2-й Страницей, и показываем их через livewire.products.load-products. Это представление также отображает кнопку «Загрузить больше продуктов» для 3-й страницы.

Таким образом, разбив функциональность на два компонента, мы решили проблему добавления в текущий список.

Теперь давайте внесем изменения, чтобы загрузить больше продуктов по мере прокрутки пользователя, а не нажатия кнопки. Нам нужно только внести изменения в представление LoadMoreProducts. Нам нужно запустить событие клика, когда пользователь прокрутит до конца списка. Мы можем сделать это, используя x-init Директиву AlpineJs.

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

    x-init="checkScroll"
>

Теперь, когда пользователь прокрутит список до конца списка, метод будет активирован, loadMore а записи будут добавлены в конец списка. Мы получим тот же результат, что и на рисунке в начале учебника.

Если вас интересует код, вы можете получить его с Github.

Надеюсь, вам понравился этот учебник. Для похожих статей вы можете следить за мной в Twitter

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

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...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297