Создание компонента выдвижной панели с помощью Livewire

  • Время чтения ~5 мин
  • 06.10.2022
Я был поклонником Laravel Livewire с момента его первого выпуска и много раз использовал его для создания отличных пользовательских интерфейсов для приложений.

Я был поклонником Laravel Livewire с момента его первого выпуска, и я много раз использовал его для создания отличных пользовательских интерфейсов для приложений. Одна из вещей, которую я часто делаю, — это создание извлеченных компонентов, в которые я могу передавать другие, например, чтобы у меня не было 20 разных модальных окон или слайдов.

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

Я предполагаю, что вы уже установили Laravel и Livewire и настроили базовое приложение. Я буду использовать Tailwind UI и Tailwind CSS для стиля, потому что понятия не имею, как что-либо проектировать.

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

php artisan livewire:make SidePanel --test

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

declare(strict_types=1);
 
namespace App\Http\Livewire;
 
use Illuminate\Contracts\View\View as ViewContract;
use Illuminate\Support\Facades\View;
use Livewire\Component;
 
final class SidePanel extends Component
{
    public bool $open = false;
 
    public function render(): ViewContract
    {
        return View::make(
            view: 'livewire.side-panel',
        );
    }
}

Здесь у нас есть стандартный компонент Livewire, настроенный на мой очень самоуверенный лад. Пока что у нас есть одно свойство, называемое open, которое мы будем «запутывать» во внешнем интерфейсе с помощью AlpineJS. Нам нужна пара других свойств, чтобы мы могли отображать панель и не падать, если компонент не передан.

declare(strict_types=1);
 
namespace App\Http\Livewire;
 
use Illuminate\Contracts\View\View as ViewContract;
use Illuminate\Support\Facades\View;
use Livewire\Component;
 
final class SidePanel extends Component
{
    public bool $open = false;
    public string $title = 'Default Panel';
    public string $component = '';
 
    public function render(): ViewContract
    {
        return View::make(
            view: 'livewire.side-panel',
        );
    }
}

У нас есть заголовок по умолчанию и свойство component, которое позволяет нам выбирать, какой компонент загружается. Таким образом, другие компоненты, взаимодействующие с ним, могут сказать ему, что загружать, и передать заголовок для отображения. Давайте взглянем на шаблон для этого компонента:

<section
    x-data="{ open: @entangle('open') }"
    @keydown.window.escape="open = false"
    x-show="open"
    x-cloak
    class="relative z-10"
    aria-labelledby="slide-over-title"
    x-ref="dialog"
    aria-modal="true"
>
 
    <div
        x-show="open"
        x-cloak
        x-transition:enter="ease-in-out duration-500"
        x-transition:enter-start="opacity-0"
        x-transition:enter-end="opacity-100"
        x-transition:leave="ease-in-out duration-500"
        x-transition:leave-start="opacity-100"
        x-transition:leave-end="opacity-0"
        class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
    ></div>
 
    <div class="fixed inset-0 overflow-hidden">
        <div class="absolute inset-0 overflow-hidden">
            <div class="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10">
 
                <div
                    x-show="open"
                    x-cloak
                    x-transition:enter="transform transition ease-in-out duration-500 sm:duration-700"
                    x-transition:enter-start="translate-x-full"
                    x-transition:enter-end="translate-x-0"
                    x-transition:leave="transform transition ease-in-out duration-500 sm:duration-700"
                    x-transition:leave-start="translate-x-0"
                    x-transition:leave-end="translate-x-full"
                    class="pointer-events-auto w-screen max-w-md"
                    @click.away="open = false"
                >
                    <div class="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl">
                        <header class="px-4 sm:px-6">
                            <div class="flex items-start justify-between">
                                <h2 class="text-lg font-medium text-gray-900" id="slide-over-title">
                                    Panel title
                                </h2>
                                <div class="ml-3 flex h-7 items-center">
                                    <button
                                        type="button"
                                        class="rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
                                        @click="open = false"
                                    >
                                        <span class="sr-only">Close panel</span>
                                        <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
                                            <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"></path>
                                        </svg>
                                    </button>
                                </div>
                            </div>
                        </header>
                        <article class="relative mt-6 flex-1 px-4 sm:px-6">
                            @if ($component)
                                @livewire($component)
                            @else
                                <div class="absolute inset-0 px-4 sm:px-6">
                                    <div class="h-full border-2 border-dashed border-gray-200" aria-hidden="true"></div>
                                </div>
                            @endif
                        </article>
                    </div>
                </div>
 
            </div>
        </div>
    </div>
</section>

Здесь у нас довольно много разметки, чтобы управлять тем, как он выглядит и ведет себя, используя @entangle для связи между AlpineJS и Livewire. Мы проверяем, установлен ли component, и, если нет, отображаем пустое состояние. Затем нам нужно вызвать это из других компонентов, отправив ему некоторые данные, чтобы мы могли выбрать компонент для загрузки и заголовок для установки. Это будет работать как с Livewire, так и с Alpine, но в моем примере я буду использовать другой компонент Livewire для запуска открытия панели.

$this->emit('openPanel', 'New Title', 'component.name.with-namespace');

Мы передаем три параметра, используя метод emit. Во-первых, название события, которое мы запускаем. Во-вторых, название панели. Наконец, мы хотим передать сам компонент, как если бы мы загружали его с помощью директивы livewire в вашем представлении.

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

declare(strict_types=1);
 
namespace App\Http\Livewire;
 
use Illuminate\Contracts\View\View as ViewContract;
use Illuminate\Support\Facades\View;
use Livewire\Component;
 
final class SidePanel extends Component
{
    public bool $open = false;
    public string $title = 'Default Panel';
    public string $component = '';
 
    protected $listeners = [
        'openPanel'
    ];
 
    public function openPanel(string $title, string $component): void
    {
        $this->open = true;
        $this->title = $title;
        $this->component = $component;
    }
 
    public function render(): ViewContract
    {
        return View::make(
            view: 'livewire.side-panel',
        );
    }
}

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

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

Как вы справляетесь с этими вариантами использования в своих проектах? Как вы думаете, что изменится в Livewire v3? Расскажите нам о своих мыслях в Твиттере.

Оригинал
Yurij Finiv

Yurij Finiv

Full stack

ABOUT

I'm full stack laravel developer

I knew my call in programming back in 2006.

WORK EXPERIENCE
CONTACT
Ukraine, Lutsk
+380979856297