Budowanie wysuwanego komponentu panelu za pomocą Livewire

  • Reading time ~ 9 min
  • 06.10.2022
Jestem fanem Laravel Livewire od momentu jego pierwszego wydania i używałem go wiele razy do tworzenia świetnych interfejsów użytkownika dla aplikacji.

Byłem fanem Laravel Livewire od czasu jego pierwszego wydania i używałem go wiele razy do tworzenia wspaniałych interfejsów użytkownika dla aplikacji. Jedną z rzeczy, które często robię, jest tworzenie wyodrębnionych komponentów, do których mogę przekazać innym - na przykład, aby nie mieć 20 różnych modów lub suwaków.

W tym samouczku omówię, w jaki sposób można utworzyć komponent typu slide-over dla aplikacji TALL Stack, abyś Ty również mógł wdrożyć to podejście.

Zakładam, że Ty zainstalowałeś już Laravel i Livewire i masz skonfigurowaną podstawową aplikację. Do stylizacji użyję Tailwind UI i Tailwind CSS, ponieważ nie mam pojęcia, jak cokolwiek zaprojektować.

Zacznijmy od stworzenia ogólnego komponentu w Livewire o nazwie SidePanel, który będzie zawierał cały kod i elementy sterujące wymagane do otwierania i zamykania panelu. Zacznijmy budować.

php artisan livewire:make SidePanel --test

Najpierw musimy mieć dostępny stan, aby mógł być otwarty lub zamknięty, co, na pewno się zgodzisz, jest istotnym aspektem panelu bocznego.

<
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',
        );
    }
}

Tutaj mamy standardowy komponent Livewire, dostosowany na mój bardzo uparty sposób. Do tej pory mamy jedną właściwość o nazwie open - którą „splączemy” na interfejsie użytkownika za pomocą AlpineJS. Potrzebujemy kilku innych właściwości, abyśmy mogli wyświetlić panel i nie zawiesić się, jeśli komponent nie zostanie przekazany.

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',
        );
    }
}

Mamy domyślny tytuł i właściwość komponent, która pozwala nam wybrać, który komponent jest ładowany. W ten sposób inne komponenty, które z nim rozmawiają, mogą mu powiedzieć, co załadować i przekazać tytuł, który ma zostać wyświetlony. Przyjrzyjmy się szablonowi tego komponentu:

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

Tutaj mamy sporo znaczników do kontrolowania, jak wygląda i zachowuje się, używając @entangle do komunikacji między AlpineJS i Livewire. Sprawdzamy, czy komponent został ustawiony, a jeśli nie, wyświetlamy pusty stan. Następnie musimy wyzwolić to z innych komponentów - wysyłając mu trochę danych, abyśmy mogli wybrać komponent do załadowania i tytuł do ustawienia. To zadziała zarówno z Livewire, jak i Alpine, ale w moim przykładzie użyję innego komponentu Livewire, aby wywołać otwarcie panelu.

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

Przekazujemy trzy parametry metodą emit. Po pierwsze, nazwa wydarzenia, które odpalamy. Po drugie, tytuł panelu. Na koniec chcemy przekazać sam komponent tak, jakbyśmy ładowali go za pomocą dyrektywy livewire w twoim widoku.

Teraz musimy poprosić nasz komponent Panelu bocznego, aby nasłuchiwał tego zdarzenia i miał metoda, która obsłuży logikę aktualizacji jej właściwości.

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',
        );
    }
}

Gdy słuchacz zaakceptuje wszystkie wymagane parametry i Alpine obsługuje stan otwarty i zamknięty - możemy zamknąć ten panel i wymienić pokazany komponent.

To podejście pozwoliło mi na stworzenie czystego użytkownika interfejsy, które otwierają oddzielny komponent w razie potrzeby. Ponadto komponent, przez który przechodzimy do panelu, może nadal być używany jako izolowany komponent dla widoku.

Jak radzisz sobie z tymi przypadkami użycia w swoich projektach? Jak myślisz, jak to się zmieni w Livewire v3? Podziel się z nami swoimi przemyśleniami na Twitterze.

Original
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