Skip to content

블레이드 템플릿

소개

블레이드는 라라벨에 포함된 간단하면서도 강력한 템플릿 엔진입니다. 일부 PHP 템플릿 엔진과는 달리 블레이드는 템플릿에서 일반 PHP 코드를 사용하는 것을 제한하지 않습니다. 실제로 모든 블레이드 템플릿은 일반 PHP 코드로 컴파일되고 수정될 때까지 캐시됩니다. 즉, 블레이드는 애플리케이션에 실질적으로 오버헤드를 추가하지 않습니다. 블레이드 템플릿 파일은 .blade.php 파일 확장자를 사용하며 일반적으로 resources/views 디렉터리에 저장됩니다.

블레이드 뷰는 전역 view 헬퍼를 사용하여 라우트 또는 컨트롤러에서 반환할 수 있습니다. 물론 에 대한 문서에서 언급했듯이 view 헬퍼의 두 번째 인수를 사용하여 데이터를 블레이드 뷰에 전달할 수 있습니다.

Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});

Livewire로 블레이드 강화하기

블레이드 템플릿을 한 단계 끌어올리고 동적 인터페이스를 쉽게 구축하고 싶으십니까? Laravel Livewire를 확인하세요. Livewire를 사용하면 일반적으로 React 또는 Vue와 같은 프런트엔드 프레임워크를 통해서만 가능했던 동적 기능으로 강화된 블레이드 컴포넌트를 작성할 수 있습니다. 이는 많은 JavaScript 프레임워크의 복잡성, 클라이언트 측 렌더링 또는 빌드 단계 없이 현대적이고 반응적인 프런트엔드를 구축하는 훌륭한 접근 방식을 제공합니다.

데이터 표시

변수를 중괄호로 묶어 블레이드 뷰에 전달된 데이터를 표시할 수 있습니다. 예를 들어 다음 라우트가 주어지면:

Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});

다음과 같이 name 변수의 내용을 표시할 수 있습니다.

안녕하세요, {{ $name }}.
lightbulb

Blade의 {{ }} echo 구문은 XSS 공격을 방지하기 위해 PHP의 htmlspecialchars 함수를 통해 자동으로 전송됩니다.

뷰에 전달된 변수의 내용을 표시하는 데에만 국한되지 않습니다. PHP 함수의 결과도 echo할 수 있습니다. 사실, Blade echo 구문 안에 원하는 모든 PHP 코드를 넣을 수 있습니다.

현재 UNIX 타임스탬프는 {{ time() }}입니다.

HTML 엔티티 인코딩

기본적으로 Blade (및 Laravel e 함수)는 HTML 엔티티를 이중으로 인코딩합니다. 이중 인코딩을 비활성화하려면 AppServiceProviderboot 메서드에서 Blade::withoutDoubleEncoding 메서드를 호출하십시오.

<?php
 
namespace App\Providers;
 
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
/**
* 모든 애플리케이션 서비스 부트스트랩
*/
public function boot(): void
{
Blade::withoutDoubleEncoding();
}
}

이스케이프되지 않은 데이터 표시

기본적으로 Blade {{ }} 구문은 XSS 공격을 방지하기 위해 PHP의 htmlspecialchars 함수를 통해 자동으로 전송됩니다. 데이터를 이스케이프하지 않으려면 다음 구문을 사용할 수 있습니다.

안녕하세요, {!! $name !!}.
exclamation

애플리케이션 사용자가 제공한 콘텐츠를 echo할 때는 매우 주의해야 합니다. 사용자 제공 데이터를 표시할 때 XSS 공격을 방지하려면 일반적으로 이스케이프된 중괄호 구문을 사용해야 합니다.

Blade와 JavaScript 프레임워크

많은 JavaScript 프레임워크도 "중괄호"를 사용하여 주어진 표현식이 브라우저에 표시되어야 함을 나타내므로 @ 기호를 사용하여 Blade 렌더링 엔진에 표현식을 그대로 유지해야 함을 알릴 수 있습니다. 예를 들어:

<h1>Laravel</h1>
 
Hello, @{{ name }}.

이 예제에서 @ 기호는 Blade에 의해 제거되지만, {{ name }} 표현식은 Blade 엔진에 의해 변경되지 않고 그대로 유지되어 JavaScript 프레임워크에서 렌더링할 수 있도록 합니다.

@ 기호는 Blade 지시어를 이스케이프 처리하는 데에도 사용될 수 있습니다:

{{-- Blade 템플릿 --}}
@@if()
 
<!-- HTML 출력 -->
@if()

JSON 렌더링

때때로 JavaScript 변수를 초기화하기 위해 JSON으로 렌더링하려는 의도로 배열을 뷰에 전달할 수 있습니다. 예를 들어:

<script>
var app = <?php echo json_encode($array); ?>;
</script>

그러나 json_encode를 수동으로 호출하는 대신 Illuminate\Support\Js::from 메서드 지시어를 사용할 수 있습니다. from 메서드는 PHP의 json_encode 함수와 동일한 인수를 허용하지만, 결과 JSON이 HTML 따옴표 내에 포함되도록 적절하게 이스케이프 처리됩니다. from 메서드는 주어진 객체 또는 배열을 유효한 JavaScript 객체로 변환하는 JSON.parse JavaScript 구문을 문자열로 반환합니다.

<script>
var app = {{ Illuminate\Support\Js::from($array) }};
</script>

최신 버전의 Laravel 애플리케이션 스켈레톤에는 Blade 템플릿 내에서 이 기능에 편리하게 접근할 수 있는 Js 파사드가 포함되어 있습니다.

<script>
var app = {{ Js::from($array) }};
</script>
exclamation

Js::from 메서드는 기존 변수를 JSON으로 렌더링하는 데만 사용해야 합니다. Blade 템플릿은 정규식을 기반으로 하며, 복잡한 표현식을 지시어에 전달하려고 시도하면 예기치 않은 오류가 발생할 수 있습니다.

@verbatim 지시어

템플릿의 많은 부분에서 JavaScript 변수를 표시하는 경우, 각 Blade 출력문을 @ 기호로 접두사로 붙일 필요가 없도록 HTML을 @verbatim 지시어로 감쌀 수 있습니다.

@verbatim
<div class="container">
Hello, {{ name }}.
</div>
@endverbatim

블레이드 지시어

템플릿 상속 및 데이터 표시 외에도 블레이드는 조건문 및 루프와 같은 일반적인 PHP 제어 구조에 대한 편리한 단축키를 제공합니다. 이러한 단축키는 PHP 제어 구조를 다루는 매우 깔끔하고 간결한 방법을 제공하는 동시에 PHP 대응 항목과도 유사하게 유지합니다.

If 문

@if, @elseif, @else, 및 @endif 지시어를 사용하여 if 문을 구성할 수 있습니다. 이러한 지시어는 PHP 대응 항목과 동일하게 작동합니다.

@if (count($records) === 1)
나는 하나의 레코드를 가지고 있습니다!
@elseif (count($records) > 1)
나는 여러 개의 레코드를 가지고 있습니다!
@else
나는 레코드가 없습니다!
@endif

편의를 위해 블레이드는 @unless 지시어도 제공합니다.

@unless (Auth::check())
로그인하지 않았습니다.
@endunless

이미 논의된 조건부 지시어 외에도 @isset@empty 지시어를 해당 PHP 함수의 편리한 단축키로 사용할 수 있습니다.

@isset($records)
// $records가 정의되었고 null이 아닙니다...
@endisset
 
@empty($records)
// $records가 "비어" 있습니다...
@endempty

인증 지시어

@auth@guest 지시어를 사용하여 현재 사용자가 인증되었는지 또는 게스트인지 빠르게 확인할 수 있습니다.

@auth
// 사용자가 인증되었습니다...
@endauth
 
@guest
// 사용자가 인증되지 않았습니다...
@endguest

필요한 경우 @auth@guest 지시어를 사용할 때 확인해야 하는 인증 가드를 지정할 수 있습니다.

@auth('admin')
// 사용자가 인증되었습니다...
@endauth
 
@guest('admin')
// 사용자가 인증되지 않았습니다...
@endguest

환경 지시어

@production 지시어를 사용하여 애플리케이션이 프로덕션 환경에서 실행 중인지 확인할 수 있습니다.

@production
// 프로덕션 특정 콘텐츠...
@endproduction

또는 @env 지시어를 사용하여 애플리케이션이 특정 환경에서 실행 중인지 확인할 수 있습니다.

@env('staging')
// 애플리케이션이 "staging"에서 실행 중입니다...
@endenv
 
@env(['staging', 'production'])
// 애플리케이션이 "staging" 또는 "production"에서 실행 중입니다...
@endenv

섹션 지시어

@hasSection 지시어를 사용하여 템플릿 상속 섹션에 콘텐츠가 있는지 확인할 수 있습니다.

@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
 
<div class="clearfix"></div>
@endif

sectionMissing 지시어를 사용하여 섹션에 콘텐츠가 없는지 확인할 수 있습니다.

@sectionMissing('navigation')
<div class="pull-right">
@include('default-navigation')
</div>
@endif

세션 지시어

@session 지시어는 세션 값이 존재하는지 확인하는 데 사용할 수 있습니다. 세션 값이 존재하면 @session@endsession 지시어 내의 템플릿 내용이 평가됩니다. @session 지시어의 내용 내에서 $value 변수를 에코하여 세션 값을 표시할 수 있습니다.

@session('status')
<div class="p-4 bg-green-100">
{{ $value }}
</div>
@endsession

Switch 구문

Switch 구문은 @switch, @case, @break, @default@endswitch 지시어를 사용하여 구성할 수 있습니다.

@switch($i)
@case(1)
첫 번째 케이스...
@break
 
@case(2)
두 번째 케이스...
@break
 
@default
기본 케이스...
@endswitch

루프

조건문 외에도 Blade는 PHP의 루프 구조를 다루기 위한 간단한 지시어를 제공합니다. 다시 말하지만, 이러한 각 지시어는 PHP와 동일하게 작동합니다.

@for ($i = 0; $i < 10; $i++)
현재 값은 {{ $i }}입니다.
@endfor
 
@foreach ($users as $user)
<p>이 사용자는 {{ $user->id }}입니다.</p>
@endforeach
 
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>사용자가 없습니다.</p>
@endforelse
 
@while (true)
<p>영원히 반복됩니다.</p>
@endwhile
lightbulb

foreach 루프를 반복하는 동안 루프 변수를 사용하여 루프의 첫 번째 또는 마지막 반복인지와 같은 루프에 대한 유용한 정보를 얻을 수 있습니다.

루프를 사용할 때 @continue@break 지시어를 사용하여 현재 반복을 건너뛰거나 루프를 종료할 수도 있습니다.

@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
 
<li>{{ $user->name }}</li>
 
@if ($user->number == 5)
@break
@endif
@endforeach

지시어 선언 내에 계속 또는 중단 조건을 포함할 수도 있습니다.

@foreach ($users as $user)
@continue($user->type == 1)
 
<li>{{ $user->name }}</li>
 
@break($user->number == 5)
@endforeach

루프 변수

foreach 루프를 반복하는 동안 루프 내에서 $loop 변수를 사용할 수 있습니다. 이 변수는 현재 루프 인덱스, 이것이 루프의 첫 번째 또는 마지막 반복인지와 같은 유용한 정보에 대한 접근을 제공합니다.

@foreach ($users as $user)
@if ($loop->first)
이것은 첫 번째 반복입니다.
@endif
 
@if ($loop->last)
이것은 마지막 반복입니다.
@endif
 
<p>이 사용자는 {{ $user->id }}입니다.</p>
@endforeach

중첩된 루프에 있는 경우 parent 속성을 통해 부모 루프의 $loop 변수에 접근할 수 있습니다.

@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
This is the first iteration of the parent loop.
@endif
@endforeach
@endforeach

$loop 변수는 또한 다양한 유용한 속성을 포함합니다:

속성 설명
$loop->index 현재 루프 반복의 인덱스입니다 (0부터 시작).
$loop->iteration 현재 루프 반복 횟수입니다 (1부터 시작).
$loop->remaining 루프에서 남은 반복 횟수입니다.
$loop->count 반복되는 배열의 총 항목 수입니다.
$loop->first 이것이 루프의 첫 번째 반복인지 여부입니다.
$loop->last 이것이 루프의 마지막 반복인지 여부입니다.
$loop->even 이것이 루프의 짝수 번째 반복인지 여부입니다.
$loop->odd 이것이 루프의 홀수 번째 반복인지 여부입니다.
$loop->depth 현재 루프의 중첩 수준입니다.
$loop->parent 중첩된 루프에서 부모 루프의 변수입니다.

조건부 클래스 & 스타일

@class 지시어는 조건에 따라 CSS 클래스 문자열을 컴파일합니다. 이 지시어는 배열의 형태로 클래스를 받습니다. 배열의 키는 추가하려는 클래스 또는 클래스들이고, 값은 boolean 표현식입니다. 배열 요소가 숫자 키를 가지는 경우, 항상 렌더링된 클래스 목록에 포함됩니다:

@php
$isActive = false;
$hasError = true;
@endphp
 
<span @class([
'p-4',
'font-bold' => $isActive,
'text-gray-500' => ! $isActive,
'bg-red' => $hasError,
])></span>
 
<span class="p-4 text-gray-500 bg-red"></span>

마찬가지로, @style 지시어를 사용하여 HTML 요소에 조건부로 인라인 CSS 스타일을 추가할 수 있습니다.

@php
$isActive = true;
@endphp
 
<span @style([
'background-color: red',
'font-weight: bold' => $isActive,
])></span>
 
<span style="background-color: red; font-weight: bold;"></span>

추가 속성

편의를 위해, @checked 지시어를 사용하여 주어진 HTML 체크박스 입력이 "checked" 상태인지 쉽게 나타낼 수 있습니다. 이 지시어는 제공된 조건이 true로 평가되면 checked를 출력합니다.

<input
type="checkbox"
name="active"
value="active"
@checked(old('active', $user->active))
/>

마찬가지로, @selected 지시어를 사용하여 주어진 select 옵션을 "selected" 상태로 해야 하는지 나타낼 수 있습니다.

<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>

또한, @disabled 지시어를 사용하여 주어진 요소를 "disabled" 상태로 해야 하는지 나타낼 수 있습니다.

<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>

게다가, @readonly 지시어를 사용하여 주어진 요소를 "readonly" 상태로 해야 하는지 나타낼 수 있습니다.

<input
type="email"
name="email"
@readonly($user->isNotAdmin())
/>

추가적으로, @required 지시어를 사용하여 주어진 요소가 "required" 상태여야 하는지 나타낼 수 있습니다.

<input
type="text"
name="title"
value="title"
@required($user->isAdmin())
/>

서브 뷰 포함하기

lightbulb

@include 디렉티브를 자유롭게 사용할 수 있지만, Blade 컴포넌트는 유사한 기능을 제공하며 데이터 및 속성 바인딩과 같은 @include 디렉티브보다 여러 가지 이점을 제공합니다.

Blade의 @include 디렉티브를 사용하면 다른 뷰 내에서 Blade 뷰를 포함할 수 있습니다. 부모 뷰에서 사용할 수 있는 모든 변수는 포함된 뷰에서 사용할 수 있습니다.

<div>
@include('shared.errors')
 
<form>
<!-- Form Contents -->
</form>
</div>

포함된 뷰는 부모 뷰에서 사용할 수 있는 모든 데이터를 상속하지만, 포함된 뷰에서 사용할 수 있도록 추가 데이터 배열을 전달할 수도 있습니다.

@include('view.name', ['status' => 'complete'])

존재하지 않는 뷰를 @include하려고 하면 Laravel에서 오류가 발생합니다. 있을 수도 있고 없을 수도 있는 뷰를 포함하려면 @includeIf 디렉티브를 사용해야 합니다.

@includeIf('view.name', ['status' => 'complete'])

주어진 부울 표현식이 true 또는 false로 평가될 경우 뷰를 @include하려면 @includeWhen@includeUnless 디렉티브를 사용할 수 있습니다.

@includeWhen($boolean, 'view.name', ['status' => 'complete'])
 
@includeUnless($boolean, 'view.name', ['status' => 'complete'])

주어진 뷰 배열에서 존재하는 첫 번째 뷰를 포함하려면 includeFirst 디렉티브를 사용할 수 있습니다.

@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])
exclamation

Blade 뷰에서 __DIR____FILE__ 상수를 사용하면 캐시된 컴파일된 뷰의 위치를 참조하므로 피해야 합니다.

컬렉션에 대한 뷰 렌더링

Blade의 @each 디렉티브를 사용하여 루프와 포함을 한 줄로 결합할 수 있습니다.

@each('view.name', $jobs, 'job')

@each 지시어의 첫 번째 인수는 배열 또는 컬렉션의 각 요소에 대해 렌더링할 뷰입니다. 두 번째 인수는 반복하려는 배열 또는 컬렉션이고, 세 번째 인수는 뷰 내에서 현재 반복에 할당될 변수 이름입니다. 예를 들어, jobs 배열을 반복하는 경우 일반적으로 뷰 내에서 각 작업에 job 변수로 접근하려 할 것입니다. 현재 반복의 배열 키는 뷰 내에서 key 변수로 사용할 수 있습니다.

@each 지시어에 네 번째 인수를 전달할 수도 있습니다. 이 인수는 지정된 배열이 비어 있을 경우 렌더링할 뷰를 결정합니다.

@each('view.name', $jobs, 'job', 'view.empty')
exclamation

@each를 통해 렌더링되는 뷰는 부모 뷰의 변수를 상속하지 않습니다. 자식 뷰에 이러한 변수가 필요한 경우 대신 @foreach@include 지시어를 사용해야 합니다.

@once 지시어

@once 지시어를 사용하면 렌더링 주기당 한 번만 평가되는 템플릿 부분을 정의할 수 있습니다. 이는 스택을 사용하여 특정 JavaScript 코드를 페이지 헤더에 푸시하는 데 유용할 수 있습니다. 예를 들어, 루프 내에서 특정 컴포넌트를 렌더링하는 경우 컴포넌트가 처음 렌더링될 때만 JavaScript를 헤더에 푸시하고 싶을 수 있습니다.

@once
@push('scripts')
<script>
// 사용자 정의 JavaScript...
</script>
@endpush
@endonce

@once 지시어는 종종 @push 또는 @prepend 지시어와 함께 사용되므로 편의를 위해 @pushOnce@prependOnce 지시어를 사용할 수 있습니다.

@pushOnce('scripts')
<script>
// 사용자 정의 JavaScript...
</script>
@endPushOnce

Raw PHP

경우에 따라서는 PHP 코드를 뷰에 삽입하는 것이 유용할 수 있습니다. Blade @php 지시어를 사용하여 템플릿 내에서 일반 PHP 블록을 실행할 수 있습니다.

@php
$counter = 1;
@endphp

또는, 클래스를 가져오기 위해 PHP를 사용해야 하는 경우 @use 지시어를 사용할 수 있습니다.

@use('App\Models\Flight')

두 번째 인수를 @use 지시어에 제공하여 가져온 클래스에 별칭을 지정할 수 있습니다.

@use('App\Models\Flight', 'FlightModel')

주석

Blade를 사용하면 뷰에 주석을 정의할 수도 있습니다. 그러나 HTML 주석과 달리 Blade 주석은 애플리케이션에서 반환된 HTML에 포함되지 않습니다.

{{-- 이 주석은 렌더링된 HTML에 나타나지 않습니다 --}}

컴포넌트

컴포넌트 및 슬롯은 섹션, 레이아웃 및 포함과 유사한 이점을 제공합니다. 그러나 컴포넌트 및 슬롯의 정신 모델을 더 쉽게 이해할 수 있다고 생각하는 사람도 있습니다. 컴포넌트를 작성하는 방법에는 클래스 기반 컴포넌트와 익명 컴포넌트의 두 가지가 있습니다.

클래스 기반 컴포넌트를 만들려면 make:component Artisan 명령어를 사용할 수 있습니다. 컴포넌트 사용 방법을 설명하기 위해 간단한 Alert 컴포넌트를 만들겠습니다. make:component 명령어는 컴포넌트를 app/View/Components 디렉토리에 배치합니다.

php artisan make:component Alert

make:component 명령어는 컴포넌트에 대한 뷰 템플릿도 만듭니다. 뷰는 resources/views/components 디렉토리에 배치됩니다. 자체 애플리케이션용 컴포넌트를 작성할 때 컴포넌트는 app/View/Components 디렉토리 및 resources/views/components 디렉토리 내에서 자동으로 검색되므로 일반적으로 추가 컴포넌트 등록이 필요하지 않습니다.

하위 디렉토리 내에 컴포넌트를 만들 수도 있습니다.

php artisan make:component Forms/Input

위 명령어는 app/View/Components/Forms 디렉토리에 Input 컴포넌트를 생성하고 뷰는 resources/views/components/forms 디렉토리에 위치하게 됩니다.

만약 익명 컴포넌트 (클래스 없이 블레이드 템플릿만 있는 컴포넌트)를 생성하고 싶다면 make:component 명령을 호출할 때 --view 플래그를 사용할 수 있습니다:

php artisan make:component forms.input --view

위 명령어는 resources/views/components/forms/input.blade.php에 블레이드 파일을 생성하고, <x-forms.input />를 통해 컴포넌트로 렌더링할 수 있습니다.

패키지 컴포넌트 수동 등록

자신만의 애플리케이션용 컴포넌트를 작성할 때, 컴포넌트는 app/View/Components 디렉토리와 resources/views/components 디렉토리 내에서 자동으로 검색됩니다.

하지만 Blade 컴포넌트를 사용하는 패키지를 빌드하는 경우, 컴포넌트 클래스와 해당 HTML 태그 별칭을 수동으로 등록해야 합니다. 일반적으로 패키지 서비스 제공자의 boot 메서드에서 컴포넌트를 등록해야 합니다:

use Illuminate\Support\Facades\Blade;
 
/**
* 패키지 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Blade::component('package-alert', Alert::class);
}

컴포넌트가 등록되면 해당 태그 별칭을 사용하여 렌더링할 수 있습니다:

<x-package-alert/>

또는, componentNamespace 메서드를 사용하여 규칙에 따라 컴포넌트 클래스를 자동 로드할 수 있습니다. 예를 들어, Nightshade 패키지에 Package\Views\Components 네임스페이스 내에 있는 CalendarColorPicker 컴포넌트가 있을 수 있습니다:

use Illuminate\Support\Facades\Blade;
 
/**
* 패키지의 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

이렇게 하면 package-name:: 구문을 사용하여 벤더 네임스페이스로 패키지 컴포넌트를 사용할 수 있습니다:

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade는 컴포넌트 이름을 파스칼 케이스로 변환하여 이 컴포넌트에 연결된 클래스를 자동으로 감지합니다. "점" 표기법을 사용하여 하위 디렉터리도 지원됩니다.

컴포넌트 렌더링하기

컴포넌트를 표시하려면 Blade 템플릿 내에서 Blade 컴포넌트 태그를 사용할 수 있습니다. Blade 컴포넌트 태그는 x- 문자열로 시작하고 컴포넌트 클래스의 케밥 케이스 이름이 뒤따릅니다:

<x-alert/>
 
<x-user-profile/>

컴포넌트 클래스가 app/View/Components 디렉터리 내에 더 깊게 중첩된 경우 . 문자를 사용하여 디렉터리 중첩을 나타낼 수 있습니다. 예를 들어, 컴포넌트가 app/View/Components/Inputs/Button.php에 있다고 가정하면 다음과 같이 렌더링할 수 있습니다:

<x-inputs.button/>

조건부로 컴포넌트를 렌더링하고 싶다면 컴포넌트 클래스에 shouldRender 메서드를 정의할 수 있습니다. shouldRender 메서드가 false를 반환하면 해당 컴포넌트는 렌더링되지 않습니다:

use Illuminate\Support\Str;
 
/**
* 컴포넌트가 렌더링되어야 하는지 여부
*/
public function shouldRender(): bool
{
return Str::length($this->message) > 0;
}

인덱스 컴포넌트

경우에 따라 컴포넌트가 컴포넌트 그룹의 일부이며, 관련된 컴포넌트들을 단일 디렉토리 내에 그룹화하고 싶을 수 있습니다. 예를 들어, 다음과 같은 클래스 구조를 가진 "카드" 컴포넌트를 상상해 보세요:

App\Views\Components\Card\Card
App\Views\Components\Card\Header
App\Views\Components\Card\Body

루트 Card 컴포넌트가 Card 디렉토리 내에 중첩되어 있으므로, <x-card.card>를 통해 컴포넌트를 렌더링해야 할 것이라고 예상할 수 있습니다. 그러나 컴포넌트의 파일 이름이 컴포넌트의 디렉토리 이름과 일치하는 경우, Laravel은 자동으로 해당 컴포넌트가 "루트" 컴포넌트라고 가정하고 디렉토리 이름을 반복하지 않고 컴포넌트를 렌더링할 수 있게 해줍니다:

<x-card>
<x-card.header>...</x-card.header>
<x-card.body>...</x-card.body>
</x-card>

컴포넌트에 데이터 전달하기

HTML 속성을 사용하여 Blade 컴포넌트에 데이터를 전달할 수 있습니다. 하드 코딩된 기본 값은 간단한 HTML 속성 문자열을 사용하여 컴포넌트에 전달할 수 있습니다. PHP 표현식과 변수는 : 문자를 접두사로 사용하는 속성을 통해 컴포넌트에 전달해야 합니다:

<x-alert type="error" :message="$message"/>

컴포넌트의 모든 데이터 속성은 클래스 생성자에서 정의해야 합니다. 컴포넌트의 모든 public 속성은 자동으로 컴포넌트의 뷰에서 사용할 수 있게 됩니다. 컴포넌트의 render 메서드에서 뷰로 데이터를 전달할 필요는 없습니다.

<?php
 
namespace App\View\Components;
 
use Illuminate\View\Component;
use Illuminate\View\View;
 
class Alert extends Component
{
/**
* 컴포넌트 인스턴스를 생성합니다.
*/
public function __construct(
public string $type,
public string $message,
) {}
 
/**
* 컴포넌트를 나타내는 뷰 / 콘텐츠를 가져옵니다.
*/
public function render(): View
{
return view('components.alert');
}
}

컴포넌트가 렌더링될 때, 컴포넌트의 public 변수의 내용을 변수 이름으로 에코하여 표시할 수 있습니다.

<div class="alert alert-{{ $type }}">
{{ $message }}
</div>

Casing

컴포넌트 생성자 인수는 camelCase를 사용하여 지정해야 하며, HTML 속성에서 인수 이름을 참조할 때는 kebab-case를 사용해야 합니다. 예를 들어, 다음 컴포넌트 생성자가 주어졌을 때:

/**
* 컴포넌트 인스턴스를 생성합니다.
*/
public function __construct(
public string $alertType,
) {}

$alertType 인수는 다음과 같이 컴포넌트에 제공될 수 있습니다.

<x-alert alert-type="danger" />

짧은 속성 구문

컴포넌트에 속성을 전달할 때 "짧은 속성" 구문을 사용할 수도 있습니다. 속성 이름이 해당 변수 이름과 일치하는 경우가 많으므로 이것이 종종 편리합니다.

{{-- 짧은 속성 구문... --}}
<x-profile :$userId :$name />
 
{{-- 와 같습니다... --}}
<x-profile :user-id="$userId" :name="$name" />

속성 렌더링 이스케이프

Alpine.js와 같은 일부 JavaScript 프레임워크에서도 콜론 접두사 속성을 사용하므로, 이중 콜론(::) 접두사를 사용하여 Blade에 해당 속성이 PHP 표현식이 아님을 알릴 수 있습니다. 예를 들어, 다음 컴포넌트가 주어졌다고 가정해 보겠습니다.

<x-button ::class="{ danger: isDeleting }">
Submit
</x-button>

다음 HTML이 Blade에 의해 렌더링됩니다.

<button :class="{ danger: isDeleting }">
Submit
</button>

컴포넌트 메서드

컴포넌트 템플릿에서 퍼블릭 변수를 사용할 수 있는 것 외에도, 컴포넌트의 모든 퍼블릭 메서드를 호출할 수 있습니다. 예를 들어, isSelected 메서드를 가진 컴포넌트를 상상해 보세요.

/**
* Determine if the given option is the currently selected option.
*/
public function isSelected(string $option): bool
{
return $option === $this->selected;
}

메서드 이름과 일치하는 변수를 호출하여 컴포넌트 템플릿에서 이 메서드를 실행할 수 있습니다.

<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
{{ $label }}
</option>

컴포넌트 클래스 내에서 속성 및 슬롯 접근하기

Blade 컴포넌트는 클래스의 render 메서드 내에서 컴포넌트 이름, 속성 및 슬롯에 접근할 수 있습니다. 그러나 이 데이터에 접근하려면 컴포넌트의 render 메서드에서 클로저를 반환해야 합니다.

use Closure;
 
/**
* 컴포넌트를 나타내는 뷰 / 콘텐츠를 가져옵니다.
*/
public function render(): Closure
{
return function () {
return '<div {{ $attributes }}>Components content</div>';
};
}

컴포넌트의 render 메서드에서 반환된 클로저는 $data 배열을 유일한 인수로 받을 수도 있습니다. 이 배열에는 컴포넌트에 대한 정보를 제공하는 몇 가지 요소가 포함됩니다.

return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
 
return '<div {{ $attributes }}>Components content</div>';
}
exclamation

$data 배열의 요소는 render 메서드에서 반환된 Blade 문자열에 직접 포함되어서는 안 됩니다. 이렇게 하면 악의적인 속성 콘텐츠를 통해 원격 코드 실행이 허용될 수 있습니다.

componentNamex- 접두사 뒤의 HTML 태그에 사용된 이름과 같습니다. 따라서 <x-alert />componentNamealert가 됩니다. attributes 요소에는 HTML 태그에 존재하는 모든 속성이 포함됩니다. slot 요소는 컴포넌트의 슬롯 내용이 포함된 Illuminate\Support\HtmlString 인스턴스입니다.

클로저는 문자열을 반환해야 합니다. 반환된 문자열이 기존 뷰에 해당하는 경우 해당 뷰가 렌더링됩니다. 그렇지 않으면 반환된 문자열은 인라인 Blade 뷰로 평가됩니다.

추가 종속성

컴포넌트가 Laravel의 서비스 컨테이너에서 종속성을 필요로 하는 경우, 컴포넌트의 데이터 속성 앞에 나열하면 컨테이너에서 자동으로 주입됩니다.

use App\Services\AlertCreator;
 
/**
* 컴포넌트 인스턴스를 생성합니다.
*/
public function __construct(
public AlertCreator $creator,
public string $type,
public string $message,
) {}

속성 / 메서드 숨기기

일부 public 메서드 또는 속성이 컴포넌트 템플릿에 변수로 노출되는 것을 방지하려면 컴포넌트의 $except 배열 속성에 추가하면 됩니다.

<?php
 
namespace App\View\Components;
 
use Illuminate\View\Component;
 
class Alert extends Component
{
/**
* 컴포넌트 템플릿에 노출되지 않아야 하는 속성 / 메서드입니다.
*
* @var array
*/
protected $except = ['type'];
 
/**
* 컴포넌트 인스턴스를 생성합니다.
*/
public function __construct(
public string $type,
) {}
}

컴포넌트 속성

컴포넌트에 데이터 속성을 전달하는 방법을 이미 살펴보았습니다. 하지만 때로는 컴포넌트가 작동하는 데 필요한 데이터의 일부가 아닌 class와 같은 추가 HTML 속성을 지정해야 할 수 있습니다. 일반적으로 이러한 추가 속성을 컴포넌트 템플릿의 루트 요소로 전달하려고 합니다. 예를 들어 다음과 같이 alert 컴포넌트를 렌더링한다고 가정해 보겠습니다.

<x-alert type="error" :message="$message" class="mt-4"/>

컴포넌트 생성자의 일부가 아닌 모든 속성은 자동으로 컴포넌트의 "속성 백"에 추가됩니다. 이 속성 백은 $attributes 변수를 통해 컴포넌트에서 자동으로 사용할 수 있게 됩니다. 모든 속성은 이 변수를 에코하여 컴포넌트 내에서 렌더링할 수 있습니다.

<div {{ $attributes }}>
<!-- 컴포넌트 내용 -->
</div>
exclamation

컴포넌트 태그 내에서 @env와 같은 디렉티브를 사용하는 것은 현재 지원되지 않습니다. 예를 들어, <x-alert :live="@env('production')"/>는 컴파일되지 않습니다.

기본 / 병합된 속성

때로는 속성의 기본값을 지정하거나 컴포넌트의 일부 속성에 추가 값을 병합해야 할 수 있습니다. 이를 위해 속성 백의 merge 메서드를 사용할 수 있습니다. 이 메서드는 컴포넌트에 항상 적용해야 하는 기본 CSS 클래스 집합을 정의하는 데 특히 유용합니다.

<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>

이 컴포넌트가 다음과 같이 사용된다고 가정해 보겠습니다.

<x-alert type="error" :message="$message" class="mb-4"/>

컴포넌트의 최종적으로 렌더링된 HTML은 다음과 같이 나타납니다.

<div class="alert alert-error mb-4">
<!-- $message 변수의 내용 -->
</div>

조건부 클래스 병합

때로는 주어진 조건이 true인 경우 클래스를 병합하고 싶을 수 있습니다. class 메서드를 통해 이를 수행할 수 있으며, 이 메서드는 추가하려는 클래스 또는 클래스를 배열 키에 포함하고 값은 부울 표현식인 클래스 배열을 허용합니다. 배열 요소가 숫자 키를 가지면 항상 렌더링된 클래스 목록에 포함됩니다.

<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
{{ $message }}
</div>

컴포넌트에 다른 속성을 병합해야 하는 경우 merge 메서드를 class 메서드에 연결할 수 있습니다.

<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
lightbulb

병합된 속성을 받지 않아야 하는 다른 HTML 요소에서 클래스를 조건부로 컴파일해야 하는 경우, @class 지시어를 사용할 수 있습니다.

클래스 외 속성 병합

class 속성이 아닌 속성을 병합할 때, merge 메서드에 제공된 값은 해당 속성의 "기본" 값으로 간주됩니다. 그러나 class 속성과 달리 이러한 속성은 주입된 속성 값과 병합되지 않습니다. 대신 덮어쓰여집니다. 예를 들어, button 컴포넌트의 구현은 다음과 같을 수 있습니다:

<button {{ $attributes->merge(['type' => 'button']) }}>
{{ $slot }}
</button>

사용자 정의 type으로 버튼 컴포넌트를 렌더링하려면 컴포넌트를 사용할 때 지정할 수 있습니다. type을 지정하지 않으면 button type이 사용됩니다.

<x-button type="submit">
Submit
</x-button>

이 예제에서 button 컴포넌트의 렌더링된 HTML은 다음과 같습니다:

<button type="submit">
Submit
</button>

class 외의 속성에 기본값과 주입된 값이 함께 결합되도록 하려면 prepends 메서드를 사용할 수 있습니다. 이 예제에서 data-controller 속성은 항상 profile-controller로 시작하며, 추가로 주입된 data-controller 값은 이 기본값 뒤에 배치됩니다:

<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
{{ $slot }}
</div>

속성 검색 및 필터링

filter 메서드를 사용하여 속성을 필터링할 수 있습니다. 이 메서드는 속성 모음에 속성을 유지하려는 경우 true를 반환해야 하는 클로저를 허용합니다.

{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}

편의를 위해 whereStartsWith 메서드를 사용하여 키가 주어진 문자열로 시작하는 모든 속성을 검색할 수 있습니다.

{{ $attributes->whereStartsWith('wire:model') }}

반대로 whereDoesntStartWith 메서드를 사용하여 키가 주어진 문자열로 시작하는 모든 속성을 제외할 수 있습니다.

{{ $attributes->whereDoesntStartWith('wire:model') }}

first 메서드를 사용하여 주어진 속성 모음에서 첫 번째 속성을 렌더링할 수 있습니다.

{{ $attributes->whereStartsWith('wire:model')->first() }}

컴포넌트에 속성이 있는지 확인하려면 has 메서드를 사용할 수 있습니다. 이 메서드는 속성 이름을 유일한 인수로 받아들이고 속성이 있는지 여부를 나타내는 부울을 반환합니다.

@if ($attributes->has('class'))
<div>Class 속성이 있습니다.</div>
@endif

배열이 has 메서드에 전달되면 이 메서드는 주어진 모든 속성이 컴포넌트에 있는지 확인합니다.

@if ($attributes->has(['name', 'class']))
<div>모든 속성이 있습니다.</div>
@endif

hasAny 메서드를 사용하여 주어진 속성 중 하나라도 컴포넌트에 있는지 확인할 수 있습니다.

@if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
<div>속성 중 하나가 있습니다.</div>
@endif

get 메서드를 사용하여 특정 속성 값을 검색할 수 있습니다.

{{ $attributes->get('class') }}

예약어

기본적으로 일부 키워드는 컴포넌트를 렌더링하기 위해 Blade 내부적으로 예약되어 있습니다. 다음 키워드는 컴포넌트 내에서 public 속성 또는 메서드 이름으로 정의할 수 없습니다.

  • data
  • render
  • resolveView
  • shouldRender
  • view
  • withAttributes
  • withName

슬롯

종종 "슬롯"을 통해 컴포넌트에 추가 콘텐츠를 전달해야 할 수 있습니다. 컴포넌트 슬롯은 $slot 변수를 에코하여 렌더링됩니다. 이 개념을 탐색하기 위해 alert 컴포넌트가 다음과 같은 마크업을 가지고 있다고 가정해 보겠습니다.

<!-- /resources/views/components/alert.blade.php -->
 
<div class="alert alert-danger">
{{ $slot }}
</div>

컴포넌트에 콘텐츠를 삽입하여 slot에 콘텐츠를 전달할 수 있습니다.

<x-alert>
<strong>이런!</strong> 문제가 발생했습니다!
</x-alert>

때로는 컴포넌트가 컴포넌트 내의 여러 위치에서 여러 개의 다른 슬롯을 렌더링해야 할 수 있습니다. "title" 슬롯을 삽입할 수 있도록 alert 컴포넌트를 수정해 보겠습니다.

<!-- /resources/views/components/alert.blade.php -->
 
<span class="alert-title">{{ $title }}</span>
 
<div class="alert alert-danger">
{{ $slot }}
</div>

x-slot 태그를 사용하여 명명된 슬롯의 콘텐츠를 정의할 수 있습니다. 명시적인 x-slot 태그 내에 없는 콘텐츠는 $slot 변수의 컴포넌트에 전달됩니다.

<x-alert>
<x-slot:title>
서버 오류
</x-slot>
 
<strong>이런!</strong> 문제가 발생했습니다!
</x-alert>

슬롯에 콘텐츠가 포함되어 있는지 확인하기 위해 슬롯의 isEmpty 메서드를 호출할 수 있습니다.

<span class="alert-title">{{ $title }}</span>
 
<div class="alert alert-danger">
@if ($slot->isEmpty())
슬롯이 비어 있으면 기본 콘텐츠입니다.
@else
{{ $slot }}
@endif
</div>

또한, hasActualContent 메소드를 사용하여 슬롯에 HTML 주석이 아닌 "실제" 콘텐츠가 있는지 확인할 수 있습니다.

@if ($slot->hasActualContent())
The scope has non-comment content.
@endif

스코프 슬롯

Vue와 같은 JavaScript 프레임워크를 사용해 보셨다면, 슬롯 내에서 컴포넌트의 데이터나 메소드에 접근할 수 있는 "스코프 슬롯"에 익숙하실 것입니다. Laravel에서는 컴포넌트에 public 메소드나 프로퍼티를 정의하고 슬롯 내에서 $component 변수를 통해 컴포넌트에 접근하여 비슷한 동작을 구현할 수 있습니다. 이 예에서는 x-alert 컴포넌트의 클래스에 public formatAlert 메소드가 정의되어 있다고 가정합니다.

<x-alert>
<x-slot:title>
{{ $component->formatAlert('Server Error') }}
</x-slot>
 
<strong>Whoops!</strong> Something went wrong!
</x-alert>

슬롯 속성

Blade 컴포넌트와 마찬가지로, CSS 클래스 이름과 같은 추가 속성을 슬롯에 할당할 수 있습니다.

<x-card class="shadow-sm">
<x-slot:heading class="font-bold">
Heading
</x-slot>
 
Content
 
<x-slot:footer class="text-sm">
Footer
</x-slot>
</x-card>

슬롯 속성을 사용하려면 슬롯 변수의 attributes 속성에 접근하면 됩니다. 속성을 사용하는 방법에 대한 자세한 내용은 컴포넌트 속성에 대한 문서를 참조하십시오.

@props([
'heading',
'footer',
])
 
<div {{ $attributes->class(['border']) }}>
<h1 {{ $heading->attributes->class(['text-lg']) }}>
{{ $heading }}
</h1>
 
{{ $slot }}
 
<footer {{ $footer->attributes->class(['text-gray-700']) }}>
{{ $footer }}
</footer>
</div>

인라인 컴포넌트 뷰

매우 작은 컴포넌트의 경우, 컴포넌트 클래스와 컴포넌트의 뷰 템플릿을 모두 관리하는 것이 번거롭게 느껴질 수 있습니다. 이러한 이유로 render 메서드에서 컴포넌트의 마크업을 직접 반환할 수 있습니다:

/**
* 컴포넌트를 나타내는 뷰 / 컨텐츠를 가져옵니다.
*/
public function render(): string
{
return <<<'blade'
<div class="alert alert-danger">
{{ $slot }}
</div>
blade;
}

인라인 뷰 컴포넌트 생성하기

인라인 뷰를 렌더링하는 컴포넌트를 생성하려면 make:component 명령을 실행할 때 inline 옵션을 사용하면 됩니다:

php artisan make:component Alert --inline

동적 컴포넌트

때로는 컴포넌트를 렌더링해야 하지만 런타임까지 어떤 컴포넌트를 렌더링해야 할지 모를 수 있습니다. 이러한 상황에서는 Laravel에 내장된 dynamic-component 컴포넌트를 사용하여 런타임 값 또는 변수를 기반으로 컴포넌트를 렌더링할 수 있습니다:

// $componentName = "secondary-button";
 
<x-dynamic-component :component="$componentName" class="mt-4" />

수동으로 컴포넌트 등록하기

exclamation

수동으로 컴포넌트를 등록하는 다음 문서는 주로 뷰 컴포넌트를 포함하는 Laravel 패키지를 작성하는 사람들에게 적용됩니다. 패키지를 작성하고 있지 않다면, 컴포넌트 문서의 이 부분은 관련이 없을 수 있습니다.

자신의 애플리케이션을 위한 컴포넌트를 작성할 때, 컴포넌트는 app/View/Components 디렉토리와 resources/views/components 디렉토리 내에서 자동으로 검색됩니다.

하지만, Blade 컴포넌트를 활용하는 패키지를 만들거나, 기존에 사용하던 방식이 아닌 다른 디렉토리에 컴포넌트를 배치하는 경우, Laravel이 컴포넌트를 찾을 수 있도록 컴포넌트 클래스와 HTML 태그 별칭을 수동으로 등록해야 합니다. 일반적으로 패키지의 서비스 제공자의 boot 메서드에서 컴포넌트를 등록해야 합니다.

use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
 
/**
* 패키지의 서비스 부트스트랩.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}

컴포넌트가 등록되면 태그 별칭을 사용하여 렌더링할 수 있습니다.

<x-package-alert/>

패키지 컴포넌트 자동 로드

또는 componentNamespace 메서드를 사용하여 규칙에 따라 컴포넌트 클래스를 자동 로드할 수 있습니다. 예를 들어, Nightshade 패키지에 Package\Views\Components 네임스페이스 내에 있는 CalendarColorPicker 컴포넌트가 있을 수 있습니다.

use Illuminate\Support\Facades\Blade;
 
/**
* 패키지의 서비스 부트스트랩.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

이렇게 하면 package-name:: 구문을 사용하여 벤더 네임스페이스로 패키지 컴포넌트를 사용할 수 있습니다.

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade는 컴포넌트 이름을 파스칼 케이스로 변환하여 해당 컴포넌트에 연결된 클래스를 자동으로 감지합니다. 하위 디렉터리도 "점" 표기법을 사용하여 지원됩니다.

익명 컴포넌트

인라인 컴포넌트와 유사하게 익명 컴포넌트는 단일 파일을 통해 컴포넌트를 관리하는 메커니즘을 제공합니다. 그러나 익명 컴포넌트는 단일 뷰 파일을 사용하며 연결된 클래스가 없습니다. 익명 컴포넌트를 정의하려면 resources/views/components 디렉터리 안에 Blade 템플릿을 배치하기만 하면 됩니다. 예를 들어, resources/views/components/alert.blade.php에 컴포넌트를 정의했다고 가정하면 다음과 같이 렌더링할 수 있습니다.

<x-alert/>

컴포넌트가 components 디렉토리 내부에서 더 깊이 중첩된 경우 . 문자를 사용하여 나타낼 수 있습니다. 예를 들어, 컴포넌트가 resources/views/components/inputs/button.blade.php에 정의되어 있다고 가정하면 다음과 같이 렌더링할 수 있습니다.

<x-inputs.button/>

익명 인덱스 컴포넌트

때로는 컴포넌트가 여러 Blade 템플릿으로 구성된 경우, 주어진 컴포넌트의 템플릿을 단일 디렉토리 내에 그룹화하고 싶을 수 있습니다. 예를 들어, 다음과 같은 디렉토리 구조를 가진 "아코디언" 컴포넌트를 상상해 보세요.

/resources/views/components/accordion.blade.php
/resources/views/components/accordion/item.blade.php

이 디렉토리 구조를 사용하면 다음과 같이 아코디언 컴포넌트와 해당 항목을 렌더링할 수 있습니다.

<x-accordion>
<x-accordion.item>
...
</x-accordion.item>
</x-accordion>

하지만 x-accordion을 통해 아코디언 컴포넌트를 렌더링하기 위해서는 다른 아코디언 관련 템플릿들과 함께 accordion 디렉토리 내에 중첩시키는 대신 "index" 아코디언 컴포넌트 템플릿을 resources/views/components 디렉토리에 배치해야 했습니다.

다행히도, Blade는 컴포넌트의 디렉토리 이름과 일치하는 파일을 해당 컴포넌트의 디렉토리 내에 배치할 수 있도록 합니다. 이 템플릿이 존재할 때, 해당 템플릿은 디렉토리 내에 중첩되어 있더라도 컴포넌트의 "root" 요소로 렌더링될 수 있습니다. 따라서, 위 예제에서 주어진 동일한 Blade 구문을 계속 사용할 수 있습니다. 그러나, 디렉토리 구조를 다음과 같이 조정할 것입니다:

/resources/views/components/accordion/accordion.blade.php
/resources/views/components/accordion/item.blade.php

데이터 속성 / 어트리뷰트

익명 컴포넌트는 연결된 클래스가 없기 때문에, 어떤 데이터를 변수로 컴포넌트에 전달해야 하는지, 어떤 어트리뷰트가 컴포넌트의 어트리뷰트 백에 배치되어야 하는지 궁금할 수 있습니다.

컴포넌트의 Blade 템플릿 상단에서 @props 지시어를 사용하여 어떤 어트리뷰트가 데이터 변수로 간주되어야 하는지 지정할 수 있습니다. 컴포넌트의 다른 모든 어트리뷰트는 컴포넌트의 어트리뷰트 백을 통해 사용할 수 있습니다. 데이터 변수에 기본값을 부여하려는 경우, 변수의 이름을 배열 키로, 기본값을 배열 값으로 지정할 수 있습니다.

<!-- /resources/views/components/alert.blade.php -->
 
@props(['type' => 'info', 'message'])
 
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>

위의 컴포넌트 정의를 감안할 때, 다음과 같이 컴포넌트를 렌더링할 수 있습니다.

<x-alert type="error" :message="$message" class="mb-4"/>

부모 데이터 접근하기

때로는 자식 컴포넌트 내부에서 부모 컴포넌트의 데이터에 접근하고 싶을 수 있습니다. 이러한 경우 @aware 지시어를 사용할 수 있습니다. 예를 들어, 부모 <x-menu>와 자식 <x-menu.item>으로 구성된 복잡한 메뉴 컴포넌트를 만들고 있다고 가정해 보겠습니다.

<x-menu color="purple">
<x-menu.item>...</x-menu.item>
<x-menu.item>...</x-menu.item>
</x-menu>

<x-menu> 컴포넌트는 다음과 같은 구현을 가질 수 있습니다.

<!-- /resources/views/components/menu/index.blade.php -->
 
@props(['color' => 'gray'])
 
<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
{{ $slot }}
</ul>

color prop은 부모(<x-menu>)에만 전달되었기 때문에 <x-menu.item> 내부에서는 사용할 수 없습니다. 하지만 @aware 지시어를 사용하면 <x-menu.item> 내부에서도 사용할 수 있게 됩니다.

<!-- /resources/views/components/menu/item.blade.php -->
 
@aware(['color' => 'gray'])
 
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
{{ $slot }}
</li>
exclamation

@aware 디렉티브는 HTML 속성을 통해 부모 컴포넌트에 명시적으로 전달되지 않은 부모 데이터를 액세스할 수 없습니다. 부모 컴포넌트에 명시적으로 전달되지 않은 기본 @props 값은 @aware 디렉티브로 액세스할 수 없습니다.

익명 컴포넌트 경로

앞서 논의한 바와 같이, 익명 컴포넌트는 일반적으로 resources/views/components 디렉토리 내에 Blade 템플릿을 배치하여 정의됩니다. 하지만 때로는 기본 경로 외에 다른 익명 컴포넌트 경로를 Laravel에 등록해야 할 수도 있습니다.

anonymousComponentPath 메서드는 익명 컴포넌트 위치의 "경로"를 첫 번째 인수로, 컴포넌트를 배치해야 하는 선택적 "네임스페이스"를 두 번째 인수로 받습니다. 일반적으로 이 메서드는 애플리케이션의 서비스 제공자 중 하나의 boot 메서드에서 호출해야 합니다.

/**
* 모든 애플리케이션 서비스 부트스트랩.
*/
public function boot(): void
{
Blade::anonymousComponentPath(__DIR__.'/../components');
}

위 예제와 같이 지정된 접두사 없이 컴포넌트 경로가 등록되면, 해당 Blade 컴포넌트에서 해당 접두사 없이 렌더링할 수 있습니다. 예를 들어, 위에서 등록된 경로에 panel.blade.php 컴포넌트가 있는 경우 다음과 같이 렌더링할 수 있습니다.

<x-panel />

접두사 "네임스페이스"는 anonymousComponentPath 메서드의 두 번째 인수로 제공할 수 있습니다.

Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');

접두사가 제공되면, 해당 "네임스페이스" 내의 컴포넌트는 컴포넌트를 렌더링할 때 컴포넌트 이름에 컴포넌트의 네임스페이스를 접두사로 추가하여 렌더링할 수 있습니다.

<x-dashboard::panel />

레이아웃 구성하기

컴포넌트를 사용한 레이아웃

대부분의 웹 애플리케이션은 다양한 페이지에서 동일한 일반 레이아웃을 유지합니다. 모든 뷰를 만들 때마다 전체 레이아웃 HTML을 반복해야 한다면 애플리케이션을 유지 관리하기가 매우 번거롭고 어려울 것입니다. 다행히도, 이 레이아웃을 단일 Blade 컴포넌트로 정의한 다음 애플리케이션 전체에서 사용하는 것이 편리합니다.

레이아웃 컴포넌트 정의하기

예를 들어 "todo" 목록 애플리케이션을 구축한다고 가정해 보겠습니다. 다음과 같은 layout 컴포넌트를 정의할 수 있습니다.

<!-- resources/views/components/layout.blade.php -->
 
<html>
<head>
<title>{{ $title ?? 'Todo Manager' }}</title>
</head>
<body>
<h1>Todos</h1>
<hr/>
{{ $slot }}
</body>
</html>

레이아웃 컴포넌트 적용하기

layout 컴포넌트가 정의되면 해당 컴포넌트를 사용하는 Blade 뷰를 만들 수 있습니다. 이 예제에서는 작업 목록을 표시하는 간단한 뷰를 정의합니다.

<!-- resources/views/tasks.blade.php -->
 
<x-layout>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>

컴포넌트에 주입되는 콘텐츠는 layout 컴포넌트 내에서 기본 $slot 변수에 제공됩니다. 보시다시피, layout$title 슬롯이 제공되면 해당 슬롯을 따르고, 그렇지 않으면 기본 제목이 표시됩니다. 컴포넌트 문서에서 설명한 표준 슬롯 구문을 사용하여 작업 목록 뷰에서 사용자 정의 제목을 주입할 수 있습니다.

<!-- resources/views/tasks.blade.php -->
 
<x-layout>
<x-slot:title>
Custom Title
</x-slot>
 
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>

이제 레이아웃과 작업 목록 뷰를 정의했으므로, 경로에서 task 뷰를 반환하기만 하면 됩니다.

use App\Models\Task;
 
Route::get('/tasks', function () {
return view('tasks', ['tasks' => Task::all()]);
});

템플릿 상속을 사용한 레이아웃

레이아웃 정의

레이아웃은 "템플릿 상속"을 통해 생성할 수도 있습니다. 이것은 컴포넌트가 도입되기 이전의 주요 애플리케이션 구축 방식이었습니다.

시작하기 위해 간단한 예시를 살펴보겠습니다. 먼저 페이지 레이아웃을 살펴볼 것입니다. 대부분의 웹 애플리케이션이 여러 페이지에서 동일한 일반 레이아웃을 유지하므로, 이 레이아웃을 단일 Blade 뷰로 정의하는 것이 편리합니다.

<!-- resources/views/layouts/app.blade.php -->
 
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
This is the master sidebar.
@show
 
<div class="container">
@yield('content')
</div>
</body>
</html>

보시다시피, 이 파일에는 일반적인 HTML 마크업이 포함되어 있습니다. 그러나 @section@yield 지시어를 주의하십시오. @section 지시어는 이름에서 알 수 있듯이 콘텐츠 섹션을 정의하는 반면, @yield 지시어는 주어진 섹션의 내용을 표시하는 데 사용됩니다.

이제 애플리케이션의 레이아웃을 정의했으므로 레이아웃을 상속하는 자식 페이지를 정의해 보겠습니다.

레이아웃 확장

자식 뷰를 정의할 때 @extends Blade 지시어를 사용하여 자식 뷰가 "상속"해야 하는 레이아웃을 지정합니다. Blade 레이아웃을 확장하는 뷰는 @section 지시어를 사용하여 레이아웃의 섹션에 콘텐츠를 삽입할 수 있습니다. 위 예에서 볼 수 있듯이, 이러한 섹션의 내용은 @yield를 사용하여 레이아웃에 표시됩니다.

<!-- resources/views/child.blade.php -->
 
@extends('layouts.app')
 
@section('title', '페이지 제목')
 
@section('sidebar')
@parent
 
<p>이것은 마스터 사이드바에 추가됩니다.</p>
@endsection
 
@section('content')
<p>이것은 본문 내용입니다.</p>
@endsection

이 예제에서 sidebar 섹션은 @parent 지시어를 사용하여 레이아웃의 사이드바에 콘텐츠를 덮어쓰는 대신 추가합니다. @parent 지시어는 뷰가 렌더링될 때 레이아웃의 콘텐츠로 대체됩니다.

lightbulb

이전 예제와는 달리, 이 sidebar 섹션은 @show 대신 @endsection으로 끝납니다. @endsection 지시어는 섹션을 정의하기만 하고, @show는 섹션을 정의하고 즉시 출력합니다.

@yield 지시어는 두 번째 매개변수로 기본값도 허용합니다. 이 값은 출력되는 섹션이 정의되지 않은 경우 렌더링됩니다.

@yield('content', '기본 내용')

CSRF 필드

애플리케이션에서 HTML 폼을 정의할 때마다 CSRF 보호 미들웨어가 요청을 검증할 수 있도록 폼에 숨겨진 CSRF 토큰 필드를 포함해야 합니다. 토큰 필드를 생성하려면 @csrf Blade 지시어를 사용할 수 있습니다.

<form method="POST" action="/profile">
@csrf
 
...
</form>

메서드 필드

HTML 폼은 PUT, PATCH 또는 DELETE 요청을 만들 수 없으므로 이러한 HTTP 동사를 스푸핑하려면 숨겨진 _method 필드를 추가해야 합니다. @method Blade 지시어가 이 필드를 생성할 수 있습니다.

<form action="/foo/bar" method="POST">
@method('PUT')
 
...
</form>

유효성 검사 오류

@error 지시어는 주어진 속성에 대한 유효성 검사 오류 메시지가 있는지 빠르게 확인하는 데 사용할 수 있습니다. @error 지시어 내에서 $message 변수를 에코하여 오류 메시지를 표시할 수 있습니다.

<!-- /resources/views/post/create.blade.php -->
 
<label for="title">게시물 제목</label>
 
<input
id="title"
type="text"
class="@error('title') is-invalid @enderror"
/>
 
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror

@error 지시어는 "if" 문으로 컴파일되므로, 속성에 대한 오류가 없을 때 콘텐츠를 렌더링하기 위해 @else 지시어를 사용할 수 있습니다.

<!-- /resources/views/auth.blade.php -->
 
<label for="email">이메일 주소</label>
 
<input
id="email"
type="email"
class="@error('email') is-invalid @else is-valid @enderror"
/>

여러 개의 폼이 있는 페이지에서 유효성 검사 오류 메시지를 검색하기 위해 @error 지시어에 두 번째 매개변수로 특정 오류 백의 이름을 전달할 수 있습니다.

<!-- /resources/views/auth.blade.php -->
 
<label for="email">이메일 주소</label>
 
<input
id="email"
type="email"
class="@error('email', 'login') is-invalid @enderror"
/>
 
@error('email', 'login')
<div class="alert alert-danger">{{ $message }}</div>
@enderror

스택

Blade를 사용하면 다른 뷰 또는 레이아웃의 다른 곳에서 렌더링할 수 있는 명명된 스택으로 푸시할 수 있습니다. 이는 자식 뷰에 필요한 JavaScript 라이브러리를 지정하는 데 특히 유용할 수 있습니다.

@push('scripts')
<script src="/example.js"></script>
@endpush

주어진 부울 표현식이 true로 평가될 경우 콘텐츠를 @push 하려면 @pushIf 지시어를 사용할 수 있습니다.

@pushIf($shouldPush, 'scripts')
<script src="/example.js"></script>
@endPushIf

스택에 필요한 만큼 여러 번 푸시할 수 있습니다. 전체 스택 콘텐츠를 렌더링하려면 @stack 지시문에 스택의 이름을 전달하세요.

<head>
<!-- 헤드 콘텐츠 -->
 
@stack('scripts')
</head>

스택의 시작 부분에 콘텐츠를 추가하려면 @prepend 지시문을 사용해야 합니다.

@push('scripts')
This will be second...
@endpush
 
// 나중에...
 
@prepend('scripts')
This will be first...
@endprepend

서비스 주입

@inject 지시문은 Laravel 서비스 컨테이너에서 서비스를 검색하는 데 사용할 수 있습니다. @inject에 전달되는 첫 번째 인수는 서비스가 배치될 변수의 이름이고, 두 번째 인수는 확인하려는 서비스의 클래스 또는 인터페이스 이름입니다.

@inject('metrics', 'App\Services\MetricsService')
 
<div>
월별 수익: {{ $metrics->monthlyRevenue() }}.
</div>

인라인 Blade 템플릿 렌더링

때로는 원시 Blade 템플릿 문자열을 유효한 HTML로 변환해야 할 수 있습니다. Blade facade에서 제공하는 render 메서드를 사용하여 이를 수행할 수 있습니다. render 메서드는 Blade 템플릿 문자열과 템플릿에 제공할 선택적 데이터 배열을 허용합니다.

use Illuminate\Support\Facades\Blade;
 
return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);

Laravel은 인라인 Blade 템플릿을 storage/framework/views 디렉토리에 작성하여 렌더링합니다. Blade 템플릿을 렌더링한 후 Laravel이 이러한 임시 파일을 제거하도록 하려면 메서드에 deleteCachedView 인수를 제공하면 됩니다.

return Blade::render(
'Hello, {{ $name }}',
['name' => 'Julian Bashir'],
deleteCachedView: true
);

블레이드 조각 렌더링

Turbohtmx와 같은 프론트엔드 프레임워크를 사용할 때 HTTP 응답 내에서 블레이드 템플릿의 일부만 반환해야 할 때가 있습니다. 블레이드 "조각"을 사용하면 바로 그렇게 할 수 있습니다. 시작하려면 블레이드 템플릿의 일부를 @fragment@endfragment 지시어 내에 배치하세요.

@fragment('user-list')
<ul>
@foreach ($users as $user)
<li>{{ $user->name }}</li>
@endforeach
</ul>
@endfragment

그런 다음 이 템플릿을 사용하는 뷰를 렌더링할 때 fragment 메서드를 호출하여 지정된 조각만 나가는 HTTP 응답에 포함되도록 지정할 수 있습니다.

return view('dashboard', ['users' => $users])->fragment('user-list');

fragmentIf 메서드를 사용하면 주어진 조건에 따라 뷰의 조각을 조건부로 반환할 수 있습니다. 그렇지 않으면 전체 뷰가 반환됩니다.

return view('dashboard', ['users' => $users])
->fragmentIf($request->hasHeader('HX-Request'), 'user-list');

fragmentsfragmentsIf 메서드를 사용하면 응답에 여러 뷰 조각을 반환할 수 있습니다. 조각은 함께 연결됩니다.

view('dashboard', ['users' => $users])
->fragments(['user-list', 'comment-list']);
 
view('dashboard', ['users' => $users])
->fragmentsIf(
$request->hasHeader('HX-Request'),
['user-list', 'comment-list']
);

블레이드 확장하기

블레이드를 사용하면 directive 메서드를 사용하여 사용자 정의 디렉티브를 정의할 수 있습니다. 블레이드 컴파일러가 사용자 정의 디렉티브를 만나면 디렉티브에 포함된 표현식과 함께 제공된 콜백을 호출합니다.

다음 예제에서는 DateTime 인스턴스여야 하는 주어진 $var의 형식을 지정하는 @datetime($var) 디렉티브를 만듭니다.

<?php
 
namespace App\Providers;
 
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
/**
* 애플리케이션 서비스 등록.
*/
public function register(): void
{
// ...
}
 
/**
* 애플리케이션 서비스 부트스트랩.
*/
public function boot(): void
{
Blade::directive('datetime', function (string $expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
}

보시다시피, 우리는 디렉티브에 전달된 모든 표현식에 format 메서드를 연결할 것입니다. 따라서 이 예제에서 이 디렉티브에 의해 생성되는 최종 PHP는 다음과 같습니다.

<?php echo ($var)->format('m/d/Y H:i'); ?>
exclamation

블레이드 디렉티브의 로직을 업데이트한 후에는 캐시된 모든 블레이드 뷰를 삭제해야 합니다. 캐시된 블레이드 뷰는 view:clear 아티즌 명령을 사용하여 제거할 수 있습니다.

사용자 정의 에코 핸들러

블레이드를 사용하여 객체를 "echo"하려고 시도하면 객체의 __toString 메서드가 호출됩니다. __toString 메서드는 PHP의 내장 "매직 메서드" 중 하나입니다. 그러나 때로는 상호 작용하는 클래스가 타사 라이브러리에 속하는 경우와 같이 주어진 클래스의 __toString 메서드를 제어할 수 없을 수도 있습니다.

이러한 경우 블레이드를 사용하면 특정 유형의 객체에 대한 사용자 정의 에코 핸들러를 등록할 수 있습니다. 이를 위해 블레이드의 stringable 메서드를 호출해야 합니다. stringable 메서드는 클로저를 허용합니다. 이 클로저는 렌더링을 담당하는 객체 유형을 타입 힌트해야 합니다. 일반적으로 stringable 메서드는 애플리케이션의 AppServiceProvider 클래스의 boot 메서드 내에서 호출해야 합니다.

use Illuminate\Support\Facades\Blade;
use Money\Money;
 
/**
* 애플리케이션 서비스 부트스트랩.
*/
public function boot(): void
{
Blade::stringable(function (Money $money) {
return $money->formatTo('en_GB');
});
}

사용자 정의 에코 핸들러가 정의되면 블레이드 템플릿에서 객체를 간단히 echo할 수 있습니다.

비용: {{ $money }}

사용자 정의 If 문

사용자 정의 지시문을 프로그래밍하는 것은 때로는 간단한 사용자 정의 조건문을 정의할 때보다 더 복잡할 수 있습니다. 이러한 이유로 Blade는 클로저를 사용하여 사용자 정의 조건 지시문을 빠르게 정의할 수 있는 Blade::if 메서드를 제공합니다. 예를 들어, 애플리케이션에 대해 구성된 기본 "디스크"를 확인하는 사용자 정의 조건을 정의해 보겠습니다. AppServiceProviderboot 메서드에서 이를 수행할 수 있습니다.

use Illuminate\Support\Facades\Blade;
 
/**
* 모든 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Blade::if('disk', function (string $value) {
return config('filesystems.default') === $value;
});
}

사용자 정의 조건이 정의되면 템플릿 내에서 사용할 수 있습니다.

@disk('local')
<!-- 애플리케이션이 로컬 디스크를 사용하고 있습니다... -->
@elsedisk('s3')
<!-- 애플리케이션이 s3 디스크를 사용하고 있습니다... -->
@else
<!-- 애플리케이션이 다른 디스크를 사용하고 있습니다... -->
@enddisk
 
@unlessdisk('local')
<!-- 애플리케이션이 로컬 디스크를 사용하고 있지 않습니다... -->
@enddisk