Blade komponensek 1. rész

Attila | 2023. 02. 12. 16:33 | Olvasási idő: 4 perc

Címkék: #Blade #Laravel 10 #Nézet (View) #npm #Tailwind #Telepítés (Installation)

Mielőtt folytatnám a felhasználói hitelesítésnek a Jetstream-et feldolgozó sorozatát, előtte muszáj foglalkoznom a Blade komponensekkel. Erre azért is van szükség, mivel a Livewire + Blade irányvonalat választottuk a Jetstream telepítésénél (ebből persze lehet sejteni, hogy majd a Livewire-rel is muszáj lesz kitérnünk). De egyelőre koncentráljunk a Blade komponensekre.
Laravel_components

Bevezetés

A Blade-ről, mint "template engine"-ről már írtam korábban többször, a nézeteink elkészítésénél már használtuk adataink megjelenítésére, de jónéhány direktívát is alkalmaztunk, amelyet a Blade szolgáltat a számunkra. Itt vannak erről az én bejegyzéseim: https://attila.gludovatz.hu/tags/48/posts, de aki a Blade hivatalos oldaláról szeretne elindulni, annak ideteszem ezt a hivatkozást is: https://laravel.com/docs/10.x/blade#blade-directives

A nézetek elkészítésének több módja is van. Ezek közül az egyiket már jól ismerjük, de egy rövid folyamatot felvázolok erről:

  1. Minden friss Laravel projektünk elején megvan a welcome.blade.php -nk, ami tartalmazza az alkalmazás futtatásakor a köszöntő kezdőoldalt.
  2. Ennek a tartalmát áthelyezhettük egy layout.blade.php (tipikusan ilyen nevű) fájlba
  3. A layout.blade.php fájlban helyőrzőket lehet létrehozni a @yield Blade direktíva segítségével, például @yield('content') -nel olyan helyet jelölünk ki, ahova majd a dinamikusan változó tartalmaink kerülnek.
  4. Más "alnézet" fájlokba pedig kiterjeszthettük a layout fájlunkat az @extends Blade direktíva segítségével és megadhattuk például a @section('content') - @endsection direktíva párossal, hogy a 'content' nevű helyre szeretnénk dinamikusan generálódó tartalmat betölteni és megjeleníteni.

Ezt a folyamatot pontról pontra ebben a bejegyzésemben végigvezettem én is. Ennek az az előnye, hogy nem különösebben nehéz módon tudunk dinamikus tartalmakat megjeleníteni az oldalainkon. Ez tekinthető egy "bottom-up" nézet tervezési és elkészítési módnak, de megközelíthetjük mindezt a másik irányból is ("top-down") és ebben fognak segíteni bennünket a Blade komponensek. Ezek a komponensek a Blade sablonok egy részhalmazának tekinthetők és lehetővé teszik számunkra, hogy újfajta, egyénileg beállítható és újrafelhasználható kódokat készítsünk. Gyakorlatilag egy építőkockának tekinthető egy komponens, amelyet több oldalon is felhasználhatunk, akár egy kicsit mindenhol másképpen is (paraméterezéssel). Ilyen építőkocka vagy komponens lehet például egy menü struktúra vagy akár egy figyelmeztető üzenet is. A Blade komponensekbe PHP és HTML kódokat írhatunk.


Anonim komponens

Leggyorsabban úgy láthatjuk ezt át, ha készítünk is rögtön egy komponenst. Ehhez egy vadonatúj 10-es verziójú Laravel keretrendszert használó projektet hozok létre.

Indítsuk el az alkalmazásunk kiszolgálását (php artisan serve). Így néz ki a legújabb Laravel v10 projektünk kezdőoldala:

A projekt innen klónozható: https://github.com/gludovatza/laravel10-components

Ez az új projekt tökéletesen alkalmas lesz arra, hogy mint egy homokozóban, eljátszadozzunk a komponenseinkkel, ha éppen úgy érezzük, hogy le szeretnénk fejleszteni, vagy ki szeretnénk próbálni egyet. Ha már elég tudással felvérteztük magunkat, akkor visszatérünk arra az irányvonalra, amikor a Jetstream-re épülő alkalmazásunkat szabjuk testre a komponensek segítségével.

A Laravel-ben kétféle komponenst tudunk használni: anonimat vagy egy teljes PHP osztály alapút. Kezdésként egy anonim komponenst hozunk létre és ismerjük meg a használatát.

A resources / views mappában létrehozok egy components nevű mappát, abban pedig egy layout.blade.php fájlt. Majd mozgassuk át ide a welcome.blade.php tartalmát úgy, hogy a <body> tag-eken belüli részt kitöröljük és csak egyetlen sort írunk bele:

Előfordulhat, hogy szükségünk lesz arra, hogy tartalmakat adjunk át a komponenseinknek a "slot"-on keresztül. Ezeket a $slot változó kiíratásával tudjuk megtenni, nagyon hasonlóan, mint amikor a bevezetésben látható példát követtük a @yield-@section páros segítségével.

De nézzük meg, hogy hogyan is történik mindez komponensekkel:

Az üresen maradt welcome.blade.php fájlunkra térjünk vissza és hozzunk létre benne az alábbi tartalmat:

<x-layout>
  Hello world!
</x-layout>

Az <x-layout> tag-re szeretném felhívni a figyelmet, mert ez nem egy létező HTML tag. Az "x" utal arra, hogy ez egy komponens része lesz, méghozzá a layout komponensé. Mentés után a böngészőben megnézhetjük az alkalmazásunkat és láthatjuk, hogy meg is jelent a köszöntés. Picit csúnyácska még, ezért közben ismerkedjünk meg a layout.blade.php fájl head részében hivatkozott Tailwind CSS alapjaival is.


Tailwind CSS keretrendszer

Telepítése a Laravel projektben

Mindenekelőtt telepítsük az alapvető kliens oldali csomagjainkat a projektünkbe az npm csomagkezelő segítségével:

npm install

Utána következhet a Tailwind telepítése Laravel-hez:

npm install -D tailwindcss postcss autoprefixer

Ezzel létrehozzuk a két beállítási, paraméterezési fájlját a Laravel projektünkben tailwind.config.js és postcss.config.js névvel:

npx tailwindcss init -p

Az új tailwind.config.js fájlt egy sorban kell módosítani (a content tömb tartalmát töltsük fel így):

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./resources/**/*.blade.php",
    "./resources/**/*.js",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

A resources / css / app.css fájlt nyissuk meg és adjuk hozzá ezt a tartalmat:

@tailwind base;
@tailwind components;
@tailwind utilities;

A terminálban futtassuk a következő parancsot:

npm run dev

Alkalmazása a Laravel projektben és az anonim komponensben

Még két utolsó módosítást meg kell tennünk a layout.blade.php fájlunkban ahhoz, hogy használni tudjuk érdemben a Tailwind-et:

  1. Töröljük ki a <style> tag-et a tartalmával együtt, mert ez beemelte korábban a Tailwind CSS kódját, de erre most már nem lesz szükségünk.
  2. Helyette ugyanoda szúrjuk be ezt a sort: @vite('resources/css/app.css')

Ha most futtatjuk az alkalmazásunkat, akkor sajnos még nem lehetünk benne biztosak, hogy már működik az alkalmazásunk a Tailwind CSS keretrendszerrel együttműködésben. Ezért módosítsuk a welcome.blade.php fájlunk kódját így:

<x-layout>
  <section class="bg-gray-300 p-4 mb-6">
    <div class="container">
      Hello world!
    </div>
  </section>
</x-layout>

Látható, hogy egy <section> és egy <div> tag-be foglaltuk a világ köszöntését, továbbá mindkét említett tag-nek adtunk meg Tailwind specifikus osztályokat. Az eredmény itt látható:

A böngészőnkben tehát így néz ki a kezdőoldalunk, amely egy komponenst használ a megjelenítésre a Tailwind CSS keretrendszer lehetőségeivel felvértezve (persze még csak nagyon egyszerűen).

Ha most azt szeretnénk, hogy a világ köszöntése háromszor jelenjen meg, akkor csak ismételjük meg az eddig használt szekció használatát:

Balra látható a kód, jobbra pedig az eredménye a böngészőben. Abban a szerencsés helyzetben vagyunk, hogy a korábbi npm run dev parancs futtatásával a Laravel Vite mindig frissíti a kódunk megjelenítését, ha elmentjük a fájlunk tartalmát (a Vite-ról is fogunk még tanulni).

Ez így egész jól átlátható kezdésnek. De még szervezzük át a komponenseinket egy kicsit:

Hozzunk létre a components mappában egy section.blade.php nevű fájlt. A tartalma pedig majdnem megegyezik a welcome nézetben látható egyik <section>-nel, de a világ köszöntése helyett használjuk benne ismét a $slot változó kiíratását:

A welcome nézet tartalmát pedig módosítsuk így:

<x-layout>
  <x-section>
    Hello world again!
  </x-section>
</x-layout>

Egyszer köszöntjük újra a világot, de már a section komponenst töltjük fel tartalommal a layout komponensen belül. Mindennek helyesen meg is kell jelennie a böngészőnkben egyszer.

De mi van akkor, ha többször szeretnénk köszönteni a világot, viszont mindig egy kicsit másképp (kinézetben)?

Alakítsuk át a welcome.blade.php-t:

<x-layout>
  <x-section>
    Hello world 1x!
  </x-section>
  <x-section>
    Hello world 2x!
  </x-section>
  <x-section>
    Hello world 3x!
  </x-section>
</x-layout>

Ez működik, de túl szürke, mindegyik section komponensünkre ugyanaz a stílusosztály(halmaz) vonatkozik. Köszöntsük a szürkén kívül másik módon, ehhez pedig használjunk egy változót és paraméterátadást. A változót a section komponensbe definiáljuk, és vizsgáljuk is meg az értékét, hogy majd mit kaphat meg.

<section class="{{ $type === 'success' ? 'bg-green-400' : 'bg-red-400' }} p-4 mb-6">

Egy feltételvizsgálattal fogjuk ellenőrizni a $type változó értékét, amit majd a welcome-ból "küldünk" neki. Alább pedig látható, hogy hogyan küldjük el a type változó értékét.

<x-layout>
  <x-section type="success">
    Hello world 1x!
  </x-section>
  <x-section type="success">
    Hello world 2x!
  </x-section>
  <x-section type="unsuccessful">
    Hello world 3x!
  </x-section>
</x-layout>

Így az első kettő szekció zöld hátterű lesz, az utolsó pedig piros hátterű, persze egyetlen ilyen komponenssel is tesztelhetjük és annak változtatjuk meg a type attribútum értékét.

Ha valamelyiknél lehagyjuk a három közül, akkor az oldalon hibát fogunk kapni, mert elvárja, hogy meglegyen a $type változó. Lehetőségünk van adatokat attribútumként hozzáadni a komponensünkhöz. Szúrjuk be a section.blade.php fájlunk elejére ezt:

@props([
  'type' => 'success'
])

Ebben az esetben a type változó alapértelmezett értéke a 'success' lesz. Le is tudjuk tesztelni, ha mondjuk a welcome nézetben a 3. <x-section> tag-ből kivesszük a type attribútumot és az értékét. Ekkor eredményül azt kapjuk, hogy már mindhárom szekciónk zöld hátterű lesz a böngészőben. Vagy ha úgy gondoljuk, akkor a 3.-nál meghagyhatjuk a type="unsuccessful"-t és az első kettőnél pedig kivehetjük a type-ot, akkor is zöld-zöld-piros hátterű eredménysort fogunk kapni. Próbáljuk ki többféle módon és nézzük meg, hogyan viselkedik.

Ez mindaddig jó, amíg csak két színnel akarunk játszani, de ha már több van, akkor egy kicsit másképp kell alkalmazni az adathalmazt. A section komponens @props részét módosítsuk:

@props([
  'type' => 'success',
  'colors' => [
    'success' => 'bg-green-400',
    'unsuccessful' => 'bg-red-400',
    'doubtful' => 'bg-gray-400'
  ]
])

Maradjon meg a type alapértelmezett értéke 'success'-ként, de tegyünk bele egy colors asszociatív tömböt, amivel így tudjuk biztosítani a típus (type) szerinti háttérszint majd a szekciónak: siker esetén zöld, sikertelenségnél piros, kétséges kimenetelnél pedig szürke lesz (ezek természetesen csak példák, bármilyen más színek és értékek is lehetnének).

Ezután a <section> class attribútumában módosítsuk az eddigi elágazást a dupla kapcsos zárójelen belül ({{ ... }}) így:

$colors[$type]

Ekkor a komponens a típus szerinti színt fogja felvenni. Nincs is más hátra, mint a welcome nézetben, amikor a három section komponenst használjuk, az elsőnél a type-ot nem kell megadni, ez lesz a sikeres (zöld), a másodiknál a type legyen doubtful, tehát szürke háttérszínt kap majd, míg az utolsónál legyen  a type attribútum értéke unsuccessful, így annak piros háttérszíne lesz.

<x-layout>
  <x-section>
    Hello world 1x!
  </x-section>
  <x-section type="doubtful">
    Hello world 2x!
  </x-section>
  <x-section type="unsuccessful">
    Hello world 3x!
  </x-section>
</x-layout>

Az eredménye pedig itt látható:

Természetesen a section komponensben lévő colors tömb értékeit bővíthetnénk például úgy, hogy ne csak háttérszínt adjunk nekik, hanem keretet is, például a success-nél 'border-green-500'-at adhatnánk hozzá. Minden csak rajtunk múlik, hogy mit és hogyan szeretnénk.

Még egy utolsó dolgot nézzünk meg!

Ha szeretnénk használni a welcome nézet section komponenseiben egy másik Tailwind osztályt a kinézet módosítására, az sajnos nem fog működni. Például a 3. section komponensnél állítsunk be egy mt-10-et, ami 2.5rem nagyságú felső margót jelent (mt=margin-top).

<x-section type="unsuccessful" class="mt-10">

Ennek következtében még nem változik a kinézet, nem fogja megkapni a nagyobb felső margót a 3. section.

Ennek érvényre juttatásához módosítanunk kell a section.blade.php-ben a <section> tag belsejét, hogy össze tudjuk vonni az esetlegesen kapott vagy itt beállított attribútumok értékeit.

Így lehet az attribútum "zsákban" lévő paramétereket és értékeiket összefésülni. Így most már működni fognak azok az osztályok is, amiket a komponens példánynál definiáltunk neki.


Összefoglalás és továbblépés

Ebben a bejegyzésben áttekintettem a komponensek alapvetéseit. Ki is próbáltam számos dolgot a gyakorlatban és bemutattam az eredményeit. Ehhez felhasználtam a Tailwind CSS keretrendszert, amit a Laravel projektünkbe telepítettem. Az itt bemutatott példák az anonim komponens típusra koncentrálódtak, viszont van még egy másik típusa, ami PHP osztályszintű komponenseket foglal magába. Ezzel fogjuk folytatni az ismerkedést, mielőtt visszatérnénk majd a Jetstream kinézetbeli testreszabásához.

A bejegyzéshez tartozó kódszintű változásainak Github commit-je itt érhető el.