ビューの共通部分の分離

ビューの共通部分とは

ビューの共通部分とは、例えば、HTMLの共通の部分や、ヘッダー、フッターなどがあります。今まで作ってきたビューの一部をもう一度見てみましょう。show-booksとshow-detail-bookを見比べてみます。

show-books

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Books一覧</title>
</head>
<body>
    <table>
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>詳細</th>
            <th>更新</th>
            <th>削除</th>
            
        </tr>
        @foreach ($books as $book)
            <tr>
                <td>{{ $book->id }}</td>
                <td>{{ $book->title }}</td>
                <td><a href="{{ route('books.detail', $book) }}">詳細</a></td>
                <td><a href="{{ route('books.edit', $book) }}">更新</a></td>
                <td>
                    <form action="{{ route('books.destroy', $book) }}" method="POST">
                        @csrf
                        @method("DELETE")
                        <button type="submit">削除</button>
                    </form>
                </td>
            </tr>
        @endforeach
    </table>
    <a href="{{ route('books.create') }}">新規作成</a>
</body>
</html>

show-detail-book

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Books一覧</title>
</head>
<body>
    <table>
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Author</th>
            <th>Price</th>
        </tr>
        <tr>
            <td>{{ $book->id }}</td>
            <td>{{ $book->title }}</td>
            <td>{{ $book->author }}</td>
            <td>{{ $book->price }}</td>
        </tr>
    </table>
    <a href="{{ route('books.show') }}">一覧に戻る</a>
</body>
</html>

上記では、以下のような部分が共通しています。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトル</title>
</head>
<body>

</body>
</html>

bodyの中は異なりますがそれ以外はほぼ共通です。titleも異なりますが、ここではtitleも共通とみなします。特にheadのmeta部分はすべてのページで共通となり、設定できる項目も豊富なため、各ビューごとに同じ内容を記述するのは非効率です。そこで、Laravelではコンポーネントというシステムで共通化を図っています。

Laravelのコンポーネント

コンポーネントにはクラスベースのコンポーネントと無名コンポーネントがあります。ここでは、クラスベースのコンポーネントを作成します。以下のコマンドを使用してコンポーネントのひな型を作成します。コンポーネント名はBookBaseとします。

php artisan make:component BookBase

上記を実行すると、app/View/Components/BookBase.phpとresources/views/components/book-base.blade.phpが作成されます。まずは、BookBase.phpを編集します。ここでは、共通化する部分のうち、titleタグに挿入するデータを受け渡しできるように設定します。

<?php

namespace App\View\Components;

use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;

class BookBase extends Component
{
    /**
     * Create a new component instance.
     */

    public $title;

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

    /**
     * Get the view / contents that represent the component.
     */
    public function render(): View|Closure|string
    {
        return view('components.book-base');
    }
}

クラスのパブリックプロパティにtitle変数を追加し、コンストラクターでtitle変数の初期化を行います。次に、book-base.blade.phpを編集します。以下のように編集し、外部からtitleタグの内容を受け取れるようにし、headのmetaデータは一括してこのファイルに記述するようにします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ $title }}</title>
</head>
<body>
    <h1>MyBooks</h1>
    {{ $slot }}
</body>
</html>

titleはコンポーネント呼び出し時に指定できるようにします。slotは共通化できない部分を埋め込むために設定しています。また、変化がわかるように共通部分としてページの先頭にh1タグでMyBooksと表示するように設定しています。次に、共通化したい各ビューを以下のように変更します。共通化したところを取り除き、x-book-baseタグで囲うだけです。

<x-book-base title="Books一覧">
    <table>
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>詳細</th>
            <th>更新</th>
            <th>削除</th>
            
        </tr>
        @foreach ($books as $book)
            <tr>
                <td>{{ $book->id }}</td>
                <td>{{ $book->title }}</td>
                <td><a href="{{ route('books.detail', $book) }}">詳細</a></td>
                <td><a href="{{ route('books.edit', $book) }}">更新</a></td>
                <td>
                    <form action="{{ route('books.destroy', $book) }}" method="POST">
                        @csrf
                        @method("DELETE")
                        <button type="submit">削除</button>
                    </form>
                </td>
            </tr>
        @endforeach
    </table>
    <a href="{{ route('books.create') }}">新規作成</a>
</x-book-base>

x-book-baseのtitle属性は、book-base.blade.phpのtitleに引き渡されます。http://localhost/books/showにアクセスして画面が正常に表示されれば成功です。

これで、ビューの共通化に成功しました。ヘッダーやフッターも共通化できるので、できれば試してみてください。

コメントを残す

CAPTCHA