В этом уроке мы реализуем Livewire Infinite Scrolling, которая автоматически загружает записи из базы данных по мере прокрутки пользователя в нижнюю часть списка. И в отличие от других примеров, которые вы, возможно, видели, мы позаботимся о том, чтобы наш код был производительным и не извлекал все записи при повторном рендеринге компонента.
Я начинаю с проекта 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
. Этот компонент будет отвечать за:
- Отображение приведенной выше кнопки Загрузить больше продуктов.
- Обработка события Click, которое принесет Продукты для 2-й и последующих Страниц.
- Условное отображение представления, связанного
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, и он будет обрабатывать следующие функциональные возможности:
- Мы увеличим
$page
свойство на 1. - Мы определим новый флаг
loadMore
и установим для него значение true. - В методе рендеринга мы проверим вышеуказанный флаг. Если этот флаг имеет значение true, мы извлекем записи из базы данных для заданного
$page
и отобразим представление, связанное сLoadProducts
компонентом. В противном случае мы просто отобразим View Related toLoadMoreProducts
, который отображает кнопку.
Вот как выглядит наш компонент 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