この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: ヘッダー/フッターの共通コンポーネント
SEOタイトル: 【Vue.js】ヘッダー/フッターの共通コンポーネントの作り方

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="1" cellspacing="1" style="width:1000px">
	<thead><tr><th style="background-color:#f39c12;color:#ffffff;text-align:left">この記事の要点</th></tr></thead>
	<tbody><tr><td style="background-color:#fef9e7"><ul>
				<li>Web アプリのヘッダー / フッターを<strong>共通コンポーネント</strong>として再利用する方法</li>
				<li><strong>Laravel Blade</strong>: <code>@include</code> / <code>@yield</code> / <code>@extends</code></li>
				<li><strong>Vue.js</strong>: コンポーネント import + <code><Header /></code> / <code><Footer /></code></li>
				<li><strong>React</strong>: コンポーネント import + JSX で配置</li>
				<li><strong>Next.js / Nuxt.js</strong>: Layout コンポーネントで自動適用</li>
			</ul></td></tr></tbody>
</table>

<p>&nbsp;</p>

<h2>Laravel Blade のパターン</h2>

<h3>方法 1: @extends と @yield(推奨)</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>@yield('title', 'デフォルトタイトル')</title>
    @yield('styles')
</head>
<body>

    @include('partials.header')

    <main>
        @yield('content')
    </main>

    @include('partials.footer')

    @yield('scripts')
</body>
</html></code></pre>

<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- resources/views/partials/header.blade.php -->
<header class="site-header">
    <h1><a href="{{ route('home') }}">My Site</a></h1>
    <nav>
        <ul>
            <li><a href="{{ route('home') }}">ホーム</a></li>
            <li><a href="{{ route('users.index') }}">ユーザー</a></li>
            @auth
                <li><a href="{{ route('profile') }}">マイページ</a></li>
                <li><a href="{{ route('logout') }}">ログアウト</a></li>
            @else
                <li><a href="{{ route('login') }}">ログイン</a></li>
            @endauth
        </ul>
    </nav>
</header>

<!-- resources/views/partials/footer.blade.php -->
<footer class="site-footer">
    <p>&copy; {{ date('Y') }} My Site</p>
</footer></code></pre>

<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- resources/views/users/index.blade.php -->
@extends('layouts.app')

@section('title', 'ユーザー一覧')

@section('content')
    <h2>ユーザー一覧</h2>
    @foreach ($users as $user)
        <p>{{ $user->name }}</p>
    @endforeach
@endsection

@section('scripts')
    <script src="{{ asset('js/users.js') }}"></script>
@endsection</code></pre>


<h3>方法 2: コンポーネント(Laravel 7+)</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- resources/views/components/site-header.blade.php -->
<header class="site-header">
    <h1>{{ $title ?? config('app.name') }}</h1>
    <nav>{{ $slot }}</nav>
</header>

<!-- 使い方 -->
<x-site-header title="My Page">
    <ul>
        <li><a href="/">ホーム</a></li>
    </ul>
</x-site-header></code></pre>


<h2>Vue.js のパターン</h2>

<h3>Vue 3 + Composition API</h3>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- components/AppHeader.vue -->
<template>
    <header class="site-header">
        <h1>
            <router-link to="/">{{ title }}</router-link>
        </h1>
        <nav>
            <router-link to="/">ホーム</router-link>
            <router-link to="/users">ユーザー</router-link>
            <span v-if="user">
                {{ user.name }} さん
                <button @click="logout">ログアウト</button>
            </span>
            <router-link v-else to="/login">ログイン</router-link>
        </nav>
    </header>
</template>

<script setup>
defineProps({ title: { type: String, default: "My Site" } });

import { useAuthStore } from "@/stores/auth";
const authStore = useAuthStore();
const user = computed(() => authStore.user);

function logout() {
    authStore.logout();
}
</script></code></pre>

<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- App.vue -->
<template>
    <AppHeader title="My Site" />
    <main>
        <router-view />
    </main>
    <AppFooter />
</template>

<script setup>
import AppHeader from "./components/AppHeader.vue";
import AppFooter from "./components/AppFooter.vue";
</script></code></pre>


<h2>React のパターン</h2>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code>// components/Header.tsx
import { Link } from "react-router-dom";
import { useAuth } from "../hooks/useAuth";

export default function Header({ title = "My Site" }) {
    const { user, logout } = useAuth();
    return (
        <header className="site-header">
            <h1><Link to="/">{title}</Link></h1>
            <nav>
                <Link to="/">ホーム</Link>
                <Link to="/users">ユーザー</Link>
                {user ? (
                    <>
                        <span>{user.name} さん</span>
                        <button onClick={logout}>ログアウト</button>
                    </>
                ) : (
                    <Link to="/login">ログイン</Link>
                )}
            </nav>
        </header>
    );
}</code></pre>

<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code>// App.tsx
import Header from "./components/Header";
import Footer from "./components/Footer";

function App() {
    return (
        <>
            <Header title="My Site" />
            <main>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/users" element={<Users />} />
                </Routes>
            </main>
            <Footer />
        </>
    );
}</code></pre>


<h2>Next.js の Layout</h2>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code>// app/layout.tsx (App Router)
import Header from "@/components/Header";
import Footer from "@/components/Footer";

export default function RootLayout({ children }) {
    return (
        <html lang="ja">
            <body>
                <Header />
                <main>{children}</main>
                <Footer />
            </body>
        </html>
    );
}

// → 全ページで自動的に Header / Footer が表示される</code></pre>


<h2>Nuxt.js の Layout</h2>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code><!-- layouts/default.vue -->
<template>
    <div>
        <AppHeader />
        <main>
            <slot />
        </main>
        <AppFooter />
    </div>
</template>

<!-- pages/users.vue → 自動的に default レイアウトが適用 -->
<template>
    <div>
        <h2>ユーザー一覧</h2>
    </div>
</template>

<!-- 別レイアウトを指定 -->
<script setup>
definePageMeta({ layout: "auth" });  // layouts/auth.vue を使う
</script></code></pre>


<h2>Web Components(純粋 HTML / JS)</h2>
<pre style="background:#0f172a;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;font-family:Consolas,Monaco,monospace;font-size:0.9em;line-height:1.5"><code>// header.js
class SiteHeader extends HTMLElement {
    connectedCallback() {
        this.innerHTML = `
            <header>
                <h1><a href="/">My Site</a></h1>
                <nav>
                    <a href="/">ホーム</a>
                    <a href="/users">ユーザー</a>
                </nav>
            </header>
        `;
    }
}
customElements.define("site-header", SiteHeader);

// HTML
<site-header></site-header></code></pre>


<h2>共通コンポーネント設計の Tips</h2>

<ul>
	<li><strong>props で柔軟性</strong>: タイトル・サブメニュー等を props で受け取って汎用化</li>
	<li><strong>slot を活用</strong>: ヘッダー内に任意の要素を差し込めるように</li>
	<li><strong>認証状態に応じて</strong>: ログイン中はマイページリンク、未ログインはログインリンク</li>
	<li><strong>アクティブリンクのハイライト</strong>: 現在ページに応じてスタイル変更</li>
	<li><strong>SP/PC で別表示</strong>: メディアクエリ + display 切替、または別コンポーネント</li>
	<li><strong>SEO への配慮</strong>: <code><header></code>, <code><nav></code>, <code><footer></code> 等の意味的タグ</li>
</ul>

<h2>関連記事</h2>

<ul>
	<li><a href="/article/20923">テンプレートの作成と共通化</a></li>
	<li><a href="/article/21303">aリンクの貼り方と動的URLの作成</a></li>
</ul>