【Laravel】レイアウトの共通化、コンポーネント、スロットの使い方
開発環境
こちらで構築した環境を使用しています。
レイアウトの共通化
resources/views
に全ページ共通のレイアウトを記述するlayouts/app.blade.php
を作成してください。
mkdir -p resources/views/layouts &&
touch resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title')</title>
<!-- Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
<!-- Styles -->
@vite('resources/css/app.css')
</head>
<body>
<header>
@include('layouts.header')
</header>
<main>
@yield('content')
</main>
<footer>
@include('layouts.footer')
</footer>
</body>
</html>
今回はヘッダーとフッターも共通のレイアウトを適用するので、layouts/header.blade.php
とlayouts/footer.blade.php
を作成してください。
touch resources/views/layouts/footer.blade.php resources/views/layouts/header.blade.php
それぞれのbladeを次のように編集してください。
<div class="max-w-7xl bg-sky-200 mx-auto py-6 px-4 sm:px-6 lg:px-8">
header
</div>
<div class="max-w-7xl bg-orange-300 mx-auto py-6 px-4 sm:px-6 lg:px-8">
footer
</div>
create.blade.php
というファイルで下記のように記述してみます。
@extends('layouts.app')
@section('title', '新規作成')
@section('content')
<form method="POST" action="{{ route('user.store') }}">
@csrf
<div>
<h1 class='text-center font-bold '>新規作成</h1>
<div class="mt-4">
<label for="name">名前</label>
<input id="name" type="text" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="name" value="{{ old('name') }}" required>
@error('name')
<div>{{ $message }}</div>
@enderror
</div>
<div class="mt-4">
<label for="email">メールアドレス</label>
<input id="email" type="email" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="email" value="{{ old('email') }}" required>
@error('email')
<div>{{ $message }}</div>
@enderror
</div>
<div class="flex items-center justify-center my-4">
<button type="submit">
登録を完了する
</button>
</div>
</form>
@endsection
次のように表示されます。先ほどのレイアウトが継承されているのがわかりますね。
また、レイアウトファイル(layouts/app.blade.php
)内で@yield('title')
が使われる場所に、'新規作成'というタイトルが表示されているのがわかると思います。
@extends
指定されたテンプレートを継承し、それを基に新しいテンプレートを作成します。
@include
指定したファイルを組み込むことができます。
@yield
セクションを定義することができます。
@section
セクション名を定義することができます。
componentsファイルの作成
componentsファイルを作成します。
今回はボタンのコンポーネントを作成したいと思います。
php artisan make:component Button
#sail環境
sail artisan make:component <コンポーネント名>
app/view/components
にファイルが作成されているか確認してください。
以下はbutton
のコンポーネントファイルです。
<button
{{ $attributes->merge(['type' => 'submit', 'class' => 'bg-gray-300']) }}>
{{ $slot }}
</button>
$attributes->merge()
親コンポーネントで渡された属性とmerge
メソッド内で指定された追加の属性をマージするために使用されます。
componentsを使うには、<x-ファイル名>
と記述します。
@extends('layouts.app')
@section('title', '新規作成')
@section('content')
<form method="POST" action="{{ route('user.store') }}">
@csrf
<div>
<h1 class='text-center font-bold '>新規作成</h1>
<div class="mt-4">
<label for="name">名前</label>
<input id="name" type="text"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
name="name" value="{{ old('name') }}" required>
@error('name')
<div>{{ $message }}</div>
@enderror
</div>
<div class="mt-4">
<label for="email">メールアドレス</label>
<input id="email" type="email"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
name="email" value="{{ old('email') }}" required>
@error('email')
<div>{{ $message }}</div>
@enderror
</div>
<div class="flex items-center justify-center my-4">
<x-button>
登録を完了する
</x-button>
</div>
</form>
@endsection
button
タグをコンポーネントを使用する記述に変更しています。
@props(['value'])
<button>
{{ $value }}
</button>
文言を変更してみます。
<x-button :value="__('文言を変更しました。')" />
@props(['value'])
@props
ディレクティブを使用して、コンポーネントが受け取るプロパティを定義しています。@props(['value'])
は、このコンポーネントがvalue
という名前のプロパティを受け取ることを宣言しています。
ちなみに、<x-label :value="$buttonText">
のように記述すると変数の値を表示することもできます。
スロット
下記で{{ $slot }}
という記述が出てきました。これをスロットといいます。
$slot
の部分はスロットに$contents
のように名前を付けても問題ないです。
<x-button>
コンポーネントのタグ内のコンテンツ(文言を変更しました。
)が、コンポーネント内のスロットに挿入され、最終的にはボタンの文言として表示されます。
つまり、スロットを使用することで、Bladeコンポーネントの外部からコンテンツを注入し、動的なコンポーネントを作成することができます。
<button>
{{ $slot }}
</button>
文言を変更してみます。
<x-button>
文言を変更しました。
</x-button>
@component
@component
と<x-コンポーネント名>
の違いは、LaravelのBladeコンポーネントと呼ばれる機能を使用するかどうかです。
@component('components.button', ['type' => 'primary', 'size' => 'large', 'disabled' => false])
文言を変更しました。
@endcomponent
@slot
Bladeコンポーネント内でスロットを定義するためにBladeテンプレート内で@component
と組み合わせて使用されます。
<button>
{{ $text }}
</button>
文言を変更してみます。
@component('components.button')
@slot('text')
文言を変更しました。
@endslot
@endcomponent
終わりに
何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉
Discussion
詳細な解説ありがとうございます。Laravel初心者です。
上の記事で環境を構築して当記事を進めているのですが、ルート(routes/web.php)の記述が見当たりませんでした。localhost/create
を開く説明がありますが、その場合、この2つのルート設定が必要と思いました。編集手順や実行するコマンド等、読み飛ばしていたらすみません。
はじめまして。コメントをいただきありがとうございます。
ご指摘の通り、記述が不足している部分がありました。
時間を見つけて記述を追加する予定です。本当に助かりました!