今回は、VueJSのコンポーネントの話ではありません。Inertiaの話でもありません。Laravelのブレードコンポーネントの話です。使い始めると結構いいものです。
デモ
こんな入力画面あるとします。
もともとのブレードは、こんな感じです。
...
<div class="card-body">
<form method="POST" action="{{ route('register') }}">
@csrf
<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">メールアドレス</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
登録
</button>
</div>
</div>
</form>
</div>
...
今度は、コンポーネントを使用した、ブレードファイルの中身を見てみましょう。
...
<div class="card-body">
<x-form action="{{ route('register') }}">
<div class="row mb-3">
<x-label name="email">メールアドレス</x-label>
<div class="col-md-6">
<x-input type="email" name="email" required autocomplete="email" />
</div>
</div>
<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<x-button type="submit" level="primary">登録</x-button>
</div>
</div>
</x-form>
</div>
...
見た目、とてもシンプルになりました。しかし、見慣れないHTMLタグがx-form, x-label, x-input, x-buttonと4つありますね。
もちろんそれらがコンポーネントなのですが、どうやってそれらのタグが利用できるようになるのでしょうか?
コンポーネントの作成
コンポーネントの作成には、2つ方法があり、app/View/Componentsのディレクトリ下にクラスファイルを作成する方法と、resources/views/componentsに匿名コンポーネントを作成する方法があります。ここでは使いやすい後者を紹介します。
先のデモの4つのコンポーネントは、以下のようなファイルに定義されています。
resources/views/components ├── button.blade.php ├── form.blade.php ├── input.blade.php └── label.blade.php
button.blade.phpというコンポーネントブレードファイルを作成すれば、それだけで、他のブレードファイルで、<x-button>のタグとして使用可能になります。
コンポーネントの定義
まずは、一番外側のx-formの定義です。
@props([
'method' => 'POST',
'action',
])
@php
$method = Str::upper($method);
@endphp
<form
method="{{ $method === 'GET' ? 'GET' : 'POST' }}"
action="{{ $action }}"
{{ $attributes }}>
@csrf
@if (! in_array($method, ['GET', 'POST']))
@method($method)
@endif
{{ $slot }}
</form>
御覧のように、通常のブレードファイルと同じように、@ifや@phpが使えます。しかし、@propsは見たことありませんね。
@propsでは、コンポーネントを使用するブレードから、コンポーネントにデータを渡すための変数の宣言と初期化をします。
ここでは、methodとactionの変数がありますが
<x-form action="{{ route('register') }}">
では、actionにしかデータを渡していません。しかし、@propsにおいてmethodのデフォルトはPOSTと指定されているので、実際に出力されるHTMLは、以下のように初期化されます。
<form method="POST" action="http://localhost/register"> <input type="hidden" name="_token" value="8GdTncryczY6s2gkHCMFYJyRlvab2tkLbVp9iRUE"> .. </form>
もう1つ重要なのは、{{ $slot }}です。
そこの部分には、<x-form>と</x-form>のタグの間の値がすべて渡されます。
x-labelでも同様に{{ $slot }}を使います。
@props([
'name',
])
<label for="{{ $name }}" class="col-md-4 col-form-label text-md-end">{{ $slot }}</label>
x-buttonも同様です。
@props([
'type' => 'button',
'level' => 'default',
])
<button type="{{ $type }}" {{ $attributes->class("btn btn-$level")}}>{{ $slot }}</button>
@attributes->classは、既存のclassの属性に引数のclassをマージします。
例えば、
<x-button type="submit" class="m-2" level="primary">登録</x-button>
なら、
<button type="submit" class="btn btn-primary m-2">登録</button>
となります。
最後に、x-inputの定義です。
@props([
'type' => 'text',
'name',
'value' => null,
])
<input
type="{{ $type }}"
name="{{ $name }}"
value="{{ old($name, $value) }}"
@error($name)
{{ $attributes->class('form-control is-invalid') }}
@else
{{ $attributes->class('form-control') }}
@enderror
/>
@error($name)
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
以下のようにコンポーネントで定義していない属性(requiredやautocomplete)も渡していますが、
<x-input type="email" name="email" required autocomplete="email" />
これらは、そのまま最終のHTMLに渡されます。
<input type="email" name="email" value="" class="form-control" required autocomplete="email">メルマガ購読の申し込みはこちらから。

