LaravelのBlade Templatesの使い方はわかっているけどLaravel 7から登場したBlade Componentsを使った経験がない人っていませんか?Blade Componentsのリリースから時間は経過しましたが本文書ではBlade Componentsについて基礎から説明を行っています。

Laravel 8ではフロントエンド側に利用されるJetStream, Breezeのパッケージの各所でBlade Componentsが利用されているのでLaravel 8を使いこなすためにはBlade Componentsの理解が必要となります。

Blade ComponentsにはClassファイルを利用するClassベースComponentsとClassファイルを利用しないAnonymous Componentsの2種類があります。本文書ではAnonymous Componentsの説明を行い、その後にClassベースComponentsの説明を行います。

本文書公開時はLaravel8を利用して動作確認を行なっています。Laravel9でも動作確認を行なっています。

Laravelの環境構築

laravel newコマンドを使って任意のフォルダにLaravelプロジェクトを作成します。プロジェクト名には任意の名前をつけてください。ここではlarave-component-learnという名前にしています。


 % laravel new laravel-component-learn

プロジェクトが完了したらプロジェクトフォルダに移動してLaravelの開発サーバを起動してください。


 % cd laravel-component-learn
 % php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

ブラウザで確認するとLaravelの初期ページの画面が表示されます。ブラウザに表示されている画面の内容はresources¥views¥welcome.blade.phpファイルに記述されているのでこのファイルを利用してComponentsの理解を深めていきます。

Laravelトップページ
Laravelトップページ

利用したLaravelのバージョンも確認しておきます。


% php artisan -V
Laravel Framework 9.36.3

welcome.blade.phpファイルを以下のように更新します。Blade Componentsの動作確認する中でCSSのclass属性を利用するためclassを簡単に扱えるようにtailwindcss2.0をcdn経由で利用しています。


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Laravel Components</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
  <h1 class="text-2xl">Laravel Components</h1>
</body>
</html>
tailwindcssの最新版を利用したい場合にはlinkのhrefにhttps://cdn.tailwindcss.comを設定してください。

Blade Componentsとは

Blade Componentsがどのようなものなのか理解するためこれまでのBlade TemplatesとBlade Componentsを利用した記述方法を比較することが一番の近道だと思います。Blade Templatesも慣れていない人にも理解してもらえるようにシンプルなコードを使って比較を行います。

Blade Componentsを使わない場合(従来のBlade)

Blade Componentsを利用しない場合は、@extend, @yield, @sectionといったディレクティブを使ってレイアウトを作成します。resources¥viewsの下にlayoutsフォルダを作成しapp.blade.phpファイルを作成します。@yield, @sectionの場所にapp.blade.phpファイルを利用するBladeファイルからコンテンツが挿入されます。


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>@yield('title')</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
  @section('sidebar')
    <p>サイドバーです。</p>
    @show

  @yield('content')
</body>
</html>

welcome.blade.phpファイルではレイアウトファイルapp.blade.phpを利用するために@extendsディレクティブでapp.blade.phpを指定します。layoutsフォルダの下にapp.blade.phpが保存されているので@extendsで指定するファイルの場所はlayouts.appと記述することができます。


@extends('layouts.app')
extendsディレクティブを利用
extendsディレクティブを利用

app.blade.phpファイルで記述したyieldディレクティブの中にwelcome.blade.phpファイルからコンテンツを挿入したい場合は@sectionディレクティブを利用します。titleタグのようにタグ間に入るコンテンツが短い場合は@sectionの第2引数にテキスト(Laravel Components)を入力することで@yield(‘title’)の部分に入力したテキストが表示されます。


@extends('layouts.app')

@section('title','Laravel Components')

sectionディレクティブでtitleを設定したtittleタグに反映されブラウザのタブに”Laravel Components”が表示されていることが確認できます。

sectionディレクティブを利用
sectionディレクティブでtitleを設定

@yield(‘content’)の場所にHTML文などを挿入したい場合は下記のように@section(‘content’)と@endsectionの間に挿入します。先ほどtitleを設定した@sectionと異なり、第2引数を使わない場合は閉じタグの@endsectionが必須となります。ここでは@sectionと@endsectionの中に1行しか記述されていませんが複数行のHTML文を挿入することができます。


@extends('layouts.app')

@section('title','Laravel Components')

@section('content')
  <h1 class="text-2xl">Laravel Components</h1>
@endsection

app.blade.phpファイルの@yield(‘content’)の部分にsectionディレクティブのcontentで設定したコンテンツが表示されていることが確認できます。

sectionディレクティブでcontentを設定
sectionディレクティブでcontentを設定

app.blade.phpファイル側で@section(‘sidebbar’)と@showを使っている箇所があります。これは@yieldと同様にwelcome.blade.phpファイル側で@section(‘sidebar’)を使ってコンテンツを表示させることができます。@yieldsとは異なり@sectionと@showを利用した場合はwelcome.blade.phpに”サイドバーです。”といったコンテンツを継承(渡す)することができます。しかし継承には注意が必要でapp.blade.phpファイル@section(‘sidebar’)で記述したコンテンツ(”サイドバーです。”)を表示させたい場合は@parentディレクティブを記述する必要があります。@parentを利用しない場合はwelcome.blade.phpの@section(‘sidebar’)に記述したコンテンツのみ表示されます。


@extends('layouts.app')

@section('title','Laravel Components')

@section('sidebar')
  @parent
  <p>サイドバーに追加できます。</p>
@endsection

@section('content')
  <h1 class="text-2xl">Laravel Components</h1>
@endsection
@yieldを利用した場合はapp.blade.phpからwelcome.blade.phpにコンテンツを渡すことができません。@section+@showを利用した場合はapp.blade.phpからwelcome.blade.phpにコンテンツを渡すことができます。渡してもらったコンテンツを表示するためには@parentディレクティブが必要となります。

ブラウザで確認すると下記のように表示されます。複数のBladeファイルを利用して1つのページを作成することができます。

Componentsを利用しない場合の記述方法
Componentsを利用しない場合の記述方法

@parentを利用していない場合も確認しておきます。


@extends('layouts.app')

@section('title','Laravel Components')

@section('sidebar')
  <p>サイドバーに追加できます。</p>
@endsection

@section('content')
  <h1 class="text-2xl">Laravel Components</h1>
@endsection

ブラウザ上には”サイドバーです。”が表示されません。

@parentを設定しない場合
@parentを設定しない場合

Blade Componentsを使う場合

Blade Componentsを利用する場合はresources¥viewsの下にcomponentsフォルダを作成してその下にapp.blade.phpファイルを作成します。Blade Componentsを利用する場合は@yieldディレクティブではなく{{ $slot }}を使います。


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Laravel Components</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
  {{ $slot }}
</body>
</html>

次にapp.blade.phpを利用するwelcome.blade.php記述方法は@extendsディレクティブではなくタグを利用します。利用するタグ名はx-{テンプレート名}となります。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
</x-app>
app.blade.phpファイルを利用しているのでblade.phpを除いたappがテンプレート名になりx-(xハイフン)を先頭についてタグ名はx-appとなります。

x-appタグの間に記述したコンテンツがapp.blade.phpの{{ $slot }}の中に展開されて表示されます。

Laravel Componentsを利用して表示
Blade Componentsを利用して表示

これがBlade Componentsの最もシンプルな利用方法です。

x-appタグでx-の後ろにappを入れただけで¥resources¥views¥components¥app.blade.phpファイルが利用できるのはLaravelが自動で¥resources¥views¥componentsにComponentsファイルがあるかチェックして読み込んでくれるためです。componentsフォルダの下にさらにlayoutsフォルダを作成しapp.blade.phpファイルを保存した場合はx-layouts.appとタグの名前が変わります。ルールに沿ってタグ名を設定する必要があります。

welcome.blade.phpファイルのx-appタグに間にコンテンツを記述することでComponentsファイルであるapp.blade.phpの{{ $slot }}に表示されることがわかりました。Blade Componentsを利用しない場合に設定したtitle, sidebarはどのように表示させるか確認していきます。

Blade Componentsでは@yieldsや@sectionディレクティブを利用するのではなくwelcome.blade.phpからのコンテンツを表示させたい部分に{{ $変数名 }}を追加します。変数名は任意の名前をつけることができここでは{{ $title }}, {{ $sidebar }}を追加します。


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ $title }}</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>

  <p>サイドバーです。</p>
  {{ $sidebar }}

  {{ $slot }}
</body>
</html>

追加が完了したらコンテンツを渡す側のwelcome.blade.phpファイルを更新します。コンテンツをapp.bladee.phpに渡すwelcome.blade.phpでは、x-slotタグを利用してname属性に変数の名前を指定しタグの中に渡したいコンテンツを入力することでapp.blade.phpファイルの$titleと$sidebarの場所にコンテンツを渡すことができます。


<x-app>
  <x-slot name="title">
    Laravel Components
  </x-slot>

  <x-slot name="sidebar">
    <p>サイドバーに追加できます。</p>
  </x-slot>

  <h1 class="text-2xl">Laravel Components</h1>
</x-app>

Blade Componentsを利用することで従来のBlade Templateを利用した方法と同じ内容を表示させることができました。個人的にはBlade Componentsの方が設定がシンプルで初めての人にもわかりやすいように思います。

Componentsを利用しない場合の記述方法
Componentsを利用して表示

Blade Componentsの設定方法

Blade Componentsを利用する場合と利用しない場合の違いが理解できたので別のBlade Componentsを作成して理解を深めていきます。冒頭でも説明したようにBlade Componentsを利用する方法には2つの方法があります。最初はAnonymous Componentsを利用します。

Blade Componentsを利用して再利用可能なコンポーネントを作成していきます。

componentsフォルダに新たにalert.blade.phpファイルを作成します。作成したAlertコンポーネント(alert.blade.php)には下記を記述します。tailwindcssのcssを適用しています。


<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>これはアラートメッセージです。</div>
  <button>×</button>
</div>

app.blade.phpファイルは$slotのみに戻しておきます。


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Laravel Components</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
  {{ $slot }}
</body>

Alertコンポーネントを利用するためにwelcome.blade.phpファイルにx-alertタグを追加します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert />
</x-app>

ブラウザで確認すると背景色が赤のメッセージバーが表示されます。

alertコンポーネントを追加
alertコンポーネントを追加

Alertコンポーネントのメッセージバーに表示されているコンテンツはalert.blade.phpファイルに直接記述していますがコンテンツを外側から更新できるようにすることで再利用可能なコンポーネントへと変更します。

$slotを利用した方法

$slotを利用することでAlertコンポーネントのコンテンツを外側から変更することが可能になります。


<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>{{ $slot }}</div>
  <button>×</button>
</div>

$slotにコンテンツを渡すためにはx-alertタグの間にコンテンツを入力します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert>これはアラートメッセージです。</x-alert>
</x-app>

ブラウザ上ではAlertコンポーネントに直接コンテンツを入力していた場合と同じ内容が表示されます。

alertコンポーネントを追加
alertコンポーネントにslotを追加

属性を利用した方法

$slotだけではなく属性を利用しpropsとしてコンテンツを渡すことができます。Alertコンポーネントの$slotを$messageに変更します。

ReactやVue.jsを使った経験がある人なら馴染みの深いpropsと同じように親コンポーネントから子コンポーネントに値を渡す際にpropsを利用します。

<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

x-alertタグにAlertコンポーネントに記述した変数$messageのmessage部分を属性として追加し表示させたいコンテンツを設定します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert message="これはアラートメッセージです。" />
</x-app>

属性を利用してもブラウザ上では$slotを利用した場合と全く同じ内容が表示されます。

alertコンポーネントを追加
属性を利用してメッセージを変更

Laravelの変数を利用した場合

ルーティングファイル内で定義した変数$messageをviewファイルに渡しその変数の中身をAlertコンポーネントに表示させる方法を確認します。コンポーネントとLaravelのデータ連携を行う際に利用することができます。

コントロールファイルの中でデータベースから取得したデータを変数に保存する場合もこの方法でコンポーネントに値を渡すことができます。

web.phpファイルを開いてwelcome.blade.phpに変数$messageを渡します。


Route::get('/', function () {
    return view('welcome',['message' => 'これはアラートメッセージです。']);
});

Laravel上で定義されている変数を利用する場合はmessage属性の前に:(コロン)をつける必要があります。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert :message="$message" />
</x-app>

ブラウザで確認すると:(コロン)をつけて変数を渡しても表示される内容は変わりません。

alertコンポーネントを追加
:(コロン)を使って変数を渡す

初期値を設定する

message属性の初期値は@propsディレクティブを利用して設定することができます。

alert.blade.phpファイルの先頭に@propsディレクティブを追加し配列を使ってmessageに初期値を設定します。配列になっているため複数の属性の初期値を設定したい場合にも対応できます。


@props(['message' => 'このメッセージはデフォルトです。' ])

<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

初期値を設定するとx-alertタグにmessage属性を設定しない場合は@propsで設定した初期値が表示されます。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert />
</x-app>

ブラウザで確認するとx-alertタグにmessage属性を設定していないのでpropsで設定した初期値が表示されることが確認できます。

propsで設定した初期値が表示
propsで設定した初期値が表示

属性を設定すると初期値は上書きされて表示されます。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert :message="$message" />
</x-app>
alertコンポーネントを追加
propsの初期値が上書きされ表示

属性で背景色を制御

メッセージの背景色を赤に固定していましたが緊急性のあるメッセージの場合は赤、緊急度のないメッセージには青のようにAlertコンポーネントの外側から背景色を変更する方法を確認していきます。中身のコンテンツだけではなく背景色も変更できればより再利用可能で汎用的なコンポーネントになります。

$type属性を新たに設定して$type属性の値によって背景色が変更できるように変更を行います。{{ }}の中で三項演算子を使って$typeがsuccessの場合はbg-green-500となりsuccess以外はbg-red-500のclassが適用されます。


@props([
  'message' => 'このメッセージはデフォルトです。',
  'type' => 'success' 
  ])

<div class="flex justify-between p-4 items-center {{ $type=='success' ? 'bg-green-500' : 'bg-red-500' }} text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

デフォルト値をsuccessにしているのでx-alertタグでtype属性を設定しなくてもbg-green-500が適用されて背景色が緑に変わります。

type属性の追加で背景色を変更
type属性の追加で背景色を変更

x-alertタグにtype属性を設定しデフォルト値ではないalertを設定します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert :message="$message" type="alert" />
</x-app>

alertを設定した場合(success以外の文字列)は背景が赤で表示されます。

propsで設定した初期値が表示
type属性をalertに設定

赤と緑にしか背景色を設定することができないのでより汎用的にするために@phpディレクティブを使います。@phpディレクティブの中ではphpのコードを記述することができます。

@phpディレクティブで定義した変数を下記のように定義し、利用することができます。


@props([
  'message' => 'このメッセージはデフォルトです。',
  'type' => 'success' 
  ])

@php
 $addClass = 'bg-yellow-500';
@endphp

<div class="flex justify-between p-4 items-center {{ $addClass }} text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

$addClassでbg-yellow-500を設定しているので背景色は黄色になります。

@phpディレクティブで変数を定義
@phpディレクティブで変数を定義

@phpディレクティブにswitch構文を追加してtypeで渡せれる値によって背景色を変更できるように設定します。@phpディレクティブで関数を利用しているのでaddClass関数を実行する際はカッコが必要となります。


@props([
  'message' => 'このメッセージはデフォルトです。',
  'type' => 'success' 
  ])

@php
 function addClass($type){
  $result = '';
  switch($type){
    case 'success':
      $result = 'bg-green-500';
      break;
    case 'info':
      $result = 'bg-blue-200';
      break;
    case 'alert':
      $result = 'bg-red-500';
      break;
    case 'warning':
      $result = 'bg-yellow-500';
      break;
    defalut:
      $result = 'bg-green-500';
  }
  return $result;
}
@endphp

<div class="flex justify-between p-4 items-center {{ addClass($type) }} text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

typeにinfoを設定すると薄いブルーが表示されます。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert :message="$message" type="info" />
</x-app>
PHPのコードを利用して背景色を変更
PHPのコードを利用して背景色を変更

@phpディレクティブの中で関数を設定していましたが関数を設定せず以下のようにも記述することができます。


@props([
  'message' => 'このメッセージはデフォルトです。',
  'type' => 'success' 
  ])

@php
switch($type){
  case 'success':
    $addClass = 'bg-green-500';
    break;
  case 'info':
    $addClass = 'bg-blue-200';
    break;
  case 'alert':
    $addClass = 'bg-red-500';
    break;
  case 'warning':
    $addClass = 'bg-yellow-500';
    break;
  defalut:
    $addClass = 'bg-green-500';
    break;
}
@endphp

<div class="flex justify-between p-4 items-center {{ $addClass }} text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

x-alertタグにclassを設定した場合

class属性をx-alertタグに追加した場合の動作確認も行っておきます。試しに文字のフォントを太くするためにfont-boldを追加してみましょう。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert :message="$message" type="info" class="font-bold" />
</x-app>

x-alertタグにclass=”font-bold”を設定してもブラウザの表示に何も変化はありません。

classを設定する場合はattributesバッグを利用することでx-alertに設定したclassを設定することができます。attributesバッグは$attributesを設定することで利用することができます。$attributesにはx-タグに設定されて属性情報が入っています。


<div {{ $attributes }} class="flex justify-between p-4 items-center {{ addClass($type) }} text-white">

ブラウザのデベロッパーツールのコンソールで要素を確認するとx-alertで設定したclassのfont-boldは設定されていますがalert.blade.phpファイル側で設定したclassが無効になっていることが確認できます。

$attributesを使ってclassを設定
$attributesを使ってclassを設定

$attributesのみではclass属性を上書きしてしまいます。上書きをさけるために$attributesのmergeメソッドを利用することでどちらのclassの設定も反映させることができます。つまりx-alertタグで設定したclassとalertコンポーネント内で設定したclassをマージすることができます。


<div {{ $attributes->merge(['class' => 'flex justify-between p-4 items-center '.addClass($type).' text-white']) }}>

ブラウザのデベロッパーツールを見ると既存のclassだけではなくx-alertタグに設定したclassのfont-boldを確認することができ、文字の太さが変更されていることもわかります。

$attributes->mergeを利用
$attributes->mergeを利用
x-alertタグのclassとalertコンポーネント内のclassでpaddingの設定に関する設定を異なる値(p-4, p-8)で設定した場合はどちらかの値が上書きされるのではなくどちらの値も要素に設定されます。

class属性以外の属性をmerge

class以外の属性もmergeを利用することができるのか確認するためにstyle属性を利用します。alertコンポーネントでmergeメソッドの中にstyle属性の設定を行います。classだけではなく複数の属性をmergeする場合は下記のように記述することができます。


<div {{ $attributes->merge([
                    'class' => 'flex justify-between p-4 items-center '.addClass($type).' text-white',
                    'style'=> 'font-size:30px;'
                    ])}}>

style属性に設定したfont-size:30pxが反映されて文字のサイズが大きくなります。

mergeでstyle属性も追加
mergeでstyle属性も追加

classのようにマージができるか確認を行うのでx-alertタグにstyle属性を追加します。font-styleでitalicを設定しています。


<x-alert :message="$message" type="info" class="font-bold" style="font-style:italic" />

ブラウザで確認するとclassのように両方のclassがマージされるのではなくx-alertタグに設定したstyle属性のみ反映されることがわかります。

style属性はマージされない
style属性はマージされない

$attributesのmergeメソッドではclass属性はマージされますがstyle属性を含め、他の属性ではマージは行われずデフォルト値として設定されます。コンポーネントタグ(x-alert)で属性を設定した場合はmergeで設定した値は上書きされます。

ClassベースComponents

これまでに動作確認を行ってきたComponentsはAnonymous Componentsで1つのファイルのみを利用して設定を行うことができました。これから説明を行うClassベースComponentsは2つのファイル(ClassファイルとBladeファイル)を利用してComponentsの処理を記述していきます。

ClassベースComponentsの作成

php artisanコマンドを利用してClassベースComponentsを作成することができます。


 % php artisan make:component Alert 
Component created successfully.

コマンドを実行すると自動で2つのファイルが作成され、app¥View¥Componentsの下にAlert.phpファイル、resources¥views¥componentsの下にalert.blade.phpファイルが作成されます。

Alert.phpファイルにはconstructorメソッドとrenderメソッドが記述されており、renderメソッドにはcomponets.alertが設定されています。指定しているcomponents.alertがコマンド実行時に自動作成されるalert.blade.phpファイルに対応します。


<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
 
    public function __construct()
    {
        //
    }

    public function render()
    {
        return view('components.alert');
    }
}

alert.blade.phpはdiv要素のみ記述されています。


<div>
  <!-- The whole future lies in uncertainty: live immediately. - Seneca -->
</div>

alert.blade.phpファイルを下記のように更新し、x-alertタグでブラウザ上にコンテンツを表示します。


<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>これはアラートメッセージです。</div>
  <button>×</button>
</div>

welcome.blade.phpファイルにx-alertタグを追加します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert />
</x-app>

ブラウザ上にメッセージが表示されます。

alertコンポーネントを追加
alertコンポーネントを追加

x-alertタグの使い方はAnonymous Componentの場合と同じですが、ClassベースComponentsの場合はx-alertタグからLaravelが自動でapp¥View¥Componentsの下にあるAlert.phpを見つけて処理を行ってくれます。Alert.phpファイルがない場合はAnonymous Componentsとしてresources¥views¥componentsにあるalert.blade.phpファイルが利用されます。

Anonymous Componentsの場合はLaravelがresources¥views¥componentsの下にあるalert.blade.phpファイルを自動で見つけてくれます。

$slotを利用した方法

$slotを利用してx-alertタグの間に記述したコンテンツを表示させます。alert.blade.phpファイルに$slotを追加します。


<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>{{ $slot }}</div>
  <button>×</button>
</div>

welcome.blade.phpファイルのx-alertタグの間にコンテンツを記述します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert>これはアラートメッセージです。</x-alert>
</x-app>

x-alertタグに記述した内容が表示されます。ClassベースComponentでもAnonymous Componentでも$slotの利用方法は変わりません。

alertコンポーネントを追加
$slotによるコンテンツの表示

属性を利用した方法

$slotではなく属性を利用した場合にコンテンツが表示されるか確認します。Anonymous Componentで行った方法と同じ方法で確認します。

alert.blade.phpファイルの$slotを$messageに変更します。


<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

x-alertタグにmessage属性を追加しコンテンツを設定します。


<x-app>
  <h1 class="text-2xl">Laravel Components</h1>
  <x-alert message="これはアラートメッセージです。" />
</x-app>

ブラウザで確認すると”ErrorException Undefined variable: message”が表示さmessageの内容をAlertコンポーネントに渡すことができません。

ファイルを更新後に変更内容が反映されない場合はphp artisan view:clearを実行してコンパイルされたviewファイルを削除してください。

ClassベースComponentではClassファイルのAlert.phpにmessage変数を定義する必要があります。


public $message;

public function __construct($message)
{
    $this->message = $message;
}

public function render()
{
    return view('components.alert');
}

定義した$messageはrender関数のviewメソッドで変数としてviewに渡す必要はありません。

定義後にはエラーが解消されmessageに設定したコンテンツが表示されます。

alertコンポーネントを追加
Alert.phpファイルでmessage変数を定義した結果

Laravelの変数を利用した場合

ルーティングファイルweb.phpからviewファイルに対してmessage変数を渡した場合はx-alertタグのmessage属性の前にコロンをつけることで渡されたmessage変数の内容を表示させることができます。これはAnonymous Componentと同じ方法です。


Route::get('/', function () {
    return view('welcome',['message' => 'これはルーティングからのアラートメッセージです。']);
});

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

ブラウザで確認するとweb.phpファイルでviewに渡されたmessage変数の内容を表示することができます。

viewに渡された変数を表示
viewに渡された変数を表示

初期値を設定する

Anonymous Componentは初期値を与えたい場合はpropsを利用することができました。Anonymous Componentと同じ方法で初期値が設定できるか確認します。

ClassベースComponentsでは@propsでmessageに初期値を与え、x-alertタグからmessage属性を削除するとエラーが発生し@propsでは初期値の設定を行うことができません。


@props([
  'message' => 'このメッセージはデフォルトです。'
  ])

<div class="flex justify-between p-4 items-center bg-red-500 text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

初期値の設定は@propsではなくAlert.phpファイルで行います。constructorメソッドの引数で$messageの初期値を設定します。


public function __construct($message="このメッセージはデフォルトです。")
{
  $this->message = $message;
}

ブラウザで確認するとconstructorメソッドで設定した初期値が表示されます。

propsで設定した初期値が表示
constructorで設定した初期値が表示

x-alertタグにmessage属性を追加してコンテンツを設定することで初期値を上書きすることができます。

属性で背景色を制御

type属性を使ってalertコンポーネントの背景色を変更できるように設定を行っていきます。属性を追加した場合はAlert.phpファイルで変数を定義する必要があります。$typeの初期値は”success”に設定しています。


public $message;
public $type;

public function __construct($message="このメッセージはデフォルトです。",$type="success")
{
  $this->message = $message;
  $this->type = $type;
}

alert.blade.phpファイルでは$typeの値によって背景色が変わるように設定を行います。


<div class="flex justify-between p-4 items-center {{ $type=='success' ? 'bg-green-500' : 'bg-red-500' }} text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

Alert.phpファイルでは$type変数に初期値を与えているのでx-alertタグではtype属性を設定せずブラウザで確認します。

type属性の追加で背景色を変更
type属性の追加で背景色を変更

x-alertタグでtypeにsuccess以外の値を設定します。


<x-alert message="これはアラートメッセージです。" type="error" />

typeの値をerrorに設定したので背景色が赤で表示されます。

propsで設定した初期値が表示
success以外の値を設定

属性はAlert.phpで定義する必要がありますが、それ以外の設定はAnonymous Componentと同じです。

2色以外の背景色を設定したい場合のコードはAlert.phpファイルの中に記述します。switch構文で$typeの値により背景色のclassを戻すaddClass関数を追加します。


public function addClass(){
  $result = '';
  switch($this->type){
    case 'success':
    $result = 'bg-green-500';
    break;
    case 'info':
    $result = 'bg-blue-200';
    break;
    case 'alert':
    $result = 'bg-red-500';
    break;
    case 'warning':
    $result = 'bg-yellow-500';
    break;
    defalut:
    $result = 'bg-green-500';
  }
  return $result;       
}

alert.blade.phpファイルにaddClass関数を追加します。addClassの後にカッコをつけるのを忘れないでください。引数は必要ありません。


<div class="flex justify-between p-4 items-center {{ $addClass() }} text-white">
  <div>{{ $message }}</div>
  <button>×</button>
</div>

x-alertタグのtype属性の値を変更することで背景色を変更することができます。


<x-alert message="これはアラートメッセージです。" type="warning" />

type属性をwarningに設定すると以下のように表示されます。

@phpディレクティブで変数を定義
addClass関数で背景色を変更

Anonymous Componentでは属性の初期値を@props、PHPのコードを@phpディレクティブを利用して行っていましたが、ClassベースComponentではそれらの処理をすべてAlert.phpファイルの中で行うことがわかりました。

ClassベースComponentでも$attributes, $attributes->mergeを利用することができます。設定方法はAnonymous Componentで同じで説明済なので”x-alertタグにclassを設定した場合”, “class属性以外の属性をmerge”を参考にしてください。

Componentsのサービスプロバイダーへの登録

php artisan make:componentコマンドで作成したAlert.phpファイルを利用する場合はx-alertタグを使っていましたが、ClassベースComponentはClassをサービスプロパイダーに登録することでタグ名を変更することできます。

app¥Providers¥AppServiceProvider.phpファイルを開いてbootメソッドに下記を追加し、BladeとAlertをimportします。


namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use App\View\Components\Alert;


class AppServiceProvider extends ServiceProvider
{

    public function register()
    {
        //
    }

    public function boot()
    {
        Blade::component('package-alert', Alert::class);
    }
}

登録が完了するとx-package-alertタグを利用してalertコンポーネントを利用することができます。


<x-package-alert message="これはアラートメッセージです。" type="warning" />

Blade TemplateとBlade Componentsの違いまたBlade ComponentsにはClass ベースComponentとAnonymous Componentがあり設定方法が異なることも理解できたかと思います。

認証機能のLaravel BreezeにもBlade Componentsが使われていますが本文書の内容を理解できればレイアウトの構成、ファイル構成も理解することができます。次回LaravelのBladeファイルでページを作成する場合はBlade Componentsを利用してレイアウトの作成を行ってみてください。