動作環境:Laravel 8
準備
ルーターでルートでindexというビューファイルが読み込まれるようにします。
routes/web.php
Route::get('/', function () { return view('index'); });
resources/views
にindex.blade.php
ファイルを作成します。
resources/views/index.blade.php
<h1>コンポーネントのテスト</h1>
ルートにアクセスして「コンポーネントのテスト」が表示されることを確認してください。
今回はこのファイルに作成したコンポーネントを配置していきます。
簡単なコンポーネント
resources/views
にcomponents
というディレクトリを新たに作ってください。
コンポーネントファイルは基本的にはこのディレクトリの中にbladeファイルを作成していきます。
はじめにwelcome.blade.php
というファイルを作成してみましょう。
resources/views/components/welcome.blade.php
<div class="welcome"> <h2>Welcome</h2> <p>これはコンポーネントです。</p> </div>
index.blade.php
でこのコンポーネントを表示します。
コンポーネントはx-コンポーネント名
でタグのように記述することで表示することができます。
今回は、welcome.blade.php
ファイルを作成したので、<x-welcome />
で表示することができます。
タグを「/」で閉じることを忘れないでください。
resources/views/index.blade.php
<h1>コンポーネントのテスト</h1> <x-welcome />
ブラウザで表示すると下記のようになっていると思います。
<h1>コンポーネントのテスト</h1> <div class="welcome"> <h2>Welcome</h2> <p>これはコンポーネントです。</p> </div>
コンポーネントに値を渡す
先ほどは固定されたHTMLを表示するだけでしたが、コンポーネントの読み込み元から値を渡して表示してみます。
試しにタイトルを変更できるようにしてみましょう。
HTMLの属性のように記述します。
resources/views/index.blade.php
<x-welcome title="タイトルの書き換え" />
これでコンポーネントでは「$title」変数が使用できるようになります。
resources/views/components/welcome.blade.php
<div class="welcome"> <h2>{{ $title }}</h2> <p>これはコンポーネントです。</p> </div>
変数を渡す場合は属性名の前に「:」を付けます。
resources/views/index.blade.php
@php $title = "タイトルの書き換え"; @endphp <x-welcome :title="$title" />
スロットでタグの中をそのまま表示
値は次のようにタグで囲んだ状態で渡すこともできます。
resources/views/index.blade.php
<x-welcome> <p>スロットメッセージ</p> </x-welcome>
コンポーネントでは$slot
という変数を使用することで表示することができます。
resources/views/components/welcome.blade.php
<div class="welcome"> <h2>Welcome</h2> {{ $slot }} </div>
複数のスロットを使用する
別々の場所にスロットで表示したいこともあると思います。
resources/views/components/welcome.blade.php
<div class="alert"> {{ $alert }} </div> <div class="welcome"> <h2>Welcome</h2> {{ $slot }} </div>
次のようにコンポーネントの中にさらにx-slot
を配置することで、別のスロットして扱われます。
この場合name
に設定した値が変数名になります。
resources/views/index.blade.php
<x-welcome> <x-slot name="alert"> <p>エラーが発生しました。</p> </x-slot> <p>スロットメッセージ</p> </x-welcome>
属性値をまとめて表示
コンポーネントの使用元でid,class
を指定したいとします。
resources/views/index.blade.php
<x-welcome class="welcome" id="welcome-id"> <p>スロットメッセージ</p> </x-welcome>
コンポーネントでは$attributes
という変数を使用することで、id,class
をひとつひとつ指定しないでも、まとめて表示することができます。
resources/views/components/welcome.blade.php
<div {{ $attributes }}> <h2>Welcome</h2> {{ $slot }} </div>
コンポーネントのクラスと組み合わせる
コンポーネント側で設定していたクラスも生かしたい場合は$attributes->merge
という機能を使います。
resources/views/components/welcome.blade.php
<div {{ $attributes->merge(['class' => 'component-welcome']) }}> <h2>Welcome</h2> {{ $slot }} </div>
attributes(属性)にデータ値を含めない
例えば次のように属性値のほかに$title
変数を扱いたいとします。
resources/views/index.blade.php
<x-welcome class="welcome" id="welcome-id" title="タイトル"> <p>スロットメッセージ</p> </x-welcome>
そのままattributes
を展開してしまうとtitle
も入ってしまいます。
次のように@props
を設定するとデータ値になりattributes
に含まれません。
resources/views/components/welcome.blade.php
@props(['title']) <div {{ $attributes->merge(['class' => 'component-welcome']) }}> <h2>{{ $title }}</h2> {{ $slot }} </div>
レイアウトテンプレートをコンポーネントで作る
今までの機能を組み合わせることでレイアウトテンプレートを作ることもできそうですね。
たとえば次のようにレイアウトファイルを作ります。
resources/views/components/layouts/app.blade.php
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>{{ $title }}</title> </head> <body> <header> <h1>{{ $title }}</h1> </header> <main>{{ $slot }}</main> <footer>© webopixel</footer> </body> </html>
index.blade.php
で次のように作成したレイアウトファイルを指定します。
components
にディレクトリを作成して配置した場合は「.」で繋げます。
layouts
ディレクトリに入れた場合は、x-layouts.app
をいう指定になります。
resources/views/index.blade.php
<x-layouts.app title="コンポーネントのテスト"> <section> <h2>コンポーネントアレイアウト</h2> <p>コンテンツ内容</p> </section> </x-layouts.app>
コンポーネントで独立したデータを扱う
たとえばコンポーネントでデータベースの値を表示したいとします。
コントローラーからメインになるビューに値を渡し、そこからコンポーネントに値を渡すことで実現できますが、コンポーネントだけでデータの取得処理を行えるようになれば、簡単に再利用できるようになり便利そうですね。
ユーザー一覧を表示するコンポーネントを作ってみましょう。
次のコマンドを実行してください。
$ php artisan make:component UserList
app/View/Components/UserList.php
とresources/views/components/user-list.blade.php
の2つのファイルが作成されます。
UserList.php
を次のように編集します。
app/View/Components/UserList.php
<?php namespace App\View\Components; use Illuminate\View\Component; use App\Models\User; class UserList extends Component { public $users; /** * Create a new component instance. * * @return void */ public function __construct() { $this->users = User::all(); } /** * Get the view / contents that represent the component. * * @return \Illuminate\Contracts\View\View|string */ public function render() { return view('components.user-list'); } }
コンポーネントは次のように作成します。
resources/views/components/user-list.blade.php
<div> <h3>ユーザー一覧</h3> @foreach ($users as $user) {{ $user->name }} @endforeach </div>
これで予めコントローラーでデータを取得しなくても、コンポーネントを読み込むだけで表示することができます。
<x-user-list />
今回は以上です。
Laravelにはコンポーネント機能自体は以前からありましたが、新しい書き方では簡潔に書けるようになりましたね。
特にReactやVueなどフロントフレームワークを使ったことがあるなら、理解は早そうですが、@component
ディレクティブの方がそれらと明示的にわかれてるので判別しやすいというのもあると思います。