404 Not Found

404 Not Found


nginx

Laravel Views and the Blade Template Engine

Blade is Laravel's "layout engine"—this is where data is transformed into the pages users see, and where layouts, components, and inheritance eliminate repetitive page code.

1. What You'll Learn


2. A True Story of a Front-End Developer

(1) Pain Point: Having to write the navigation bar repeatedly on every page

Charlie wrote 10 pages for ShopMetrics, manually copying 60 lines of navigation bar HTML into each one. When Bob asked to move the "Pricing" link from the navigation bar to a drop-down menu, Charlie had to edit all 10 files one by one—but when he got to the seventh file, he missed a class, causing the navigation bar styles to be inconsistent on the live site, which led to three complaints from Alice.

(2) Solutions for the Blade Layout

Blade uses @extends to inherit the layout and @section to populate the content; the navigation bar is defined only once and is automatically synchronized across the entire site.

PHP
// resources/views/layouts/app.blade.php — Define layout once
<body>
    <nav>...</nav>  <!-- Navigation appears on every page -->
    @yield('content')  <!-- Each page fills this slot -->
</body>

// resources/views/shops/index.blade.php — Extend and fill
@extends('layouts.app')
@section('content')
    <h1>All Shops</h1>
@endsection

(3) Revenue

After Charlie implemented the Blade layout, the navigation bar only required maintenance of a single file. Bob's change request went from "modifying 10 files" to "modifying 1 file," with zero omissions.


3. Blade Layout Inheritance

(1) Defining the Layout

HTML
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>@yield('title', 'ShopMetrics')</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
    @include('partials.navbar')
    <main class="container mx-auto">
        @yield('content')
    </main>
    @include('partials.footer')
</body>
</html>

(2) Inheriting Layouts

HTML
<!-- resources/views/shops/index.blade.php -->
@extends('layouts.app')

@section('title', 'All Shops')

@section('content')
    <div class="grid grid-cols-3 gap-4">
        @foreach($shops as $shop)
            <div class="card">{{ $shop->name }}</div>
        @endforeach
    </div>
@endsection
Command Function Analogy
@extends Specify the layout to inherit from Select a template
@section Define content blocks Fill in the blanks in the template
@yield Output content block Placeholder in the template
@include Import Subview Insert Public Snippet

(1) ▶ Example: ShopMetrics Two-Column Layout

HTML
<!-- resources/views/layouts/dashboard.blade.php -->
@extends('layouts.app')

@section('content')
    <div class="flex">
        @include('partials.sidebar')
        <div class="flex-1 p-6">
            @yield('dashboard-content')
        </div>
    </div>
@endsection

<!-- resources/views/dashboard/analytics.blade.php -->
@extends('layouts.dashboard')

@section('title', 'Analytics Dashboard')

@section('dashboard-content')
    <h1>Analytics Overview</h1>
    <div id="chart"></div>
@endsection

Output:

TEXT
// Execution Successful

4. Control Structures

(1) Conditional Statements

PHP
@if($shop->is_active)
    <span class="badge-green">Active</span>
@elseif($shop->is_suspended)
    <span class="badge-yellow">Suspended</span>
@else
    <span class="badge-gray">Inactive</span>
@endif

@auth
    <a href="{{ route('dashboard') }}">Dashboard</a>
@endauth

@guest
    <a href="{{ route('login') }}">Login</a>
@endguest

(2) Loop Statements

PHP
@foreach($shops as $shop)
    <tr>
        <td>{{ $shop->name }}</td>
        <td>{{ $shop->revenue }}</td>
    </tr>
    @if($loop->last)
        </tbody></table>
    @endif
@endforeach

@forelse($orders as $order)
    <li>{{ $order->total }}</li>
@empty
    <li>No orders yet.</li>
@endforelse
Loop Variable Description
$loop->index Current Index (starting at 0)
$loop->iteration Current Round (starting from 1)
$loop->first Is this the first one?
$loop->last Is this the last one?
$loop->count Total

(1) ▶ Example: Conditional Rendering in the ShopMetrics Dashboard

HTML
<!-- resources/views/dashboard/index.blade.php -->
@extends('layouts.dashboard')

@section('dashboard-content')
    @auth
        <h1>Welcome, {{ auth()->user()->name }}!</h1>
    @endauth

    @if($shops->count() > 0)
        <div class="grid grid-cols-3 gap-4">
            @foreach($shops as $shop)
                <div class="card {{ $loop->first ? 'border-blue-500' : '' }}">
                    <h3>{{ $shop->name }}</h3>
                    <p>Revenue: ${{ number_format($shop->revenue, 2) }}</p>
                </div>
            @endforeach
        </div>
    @else
        <p>No shops yet. <a href="{{ route('shops.create') }}">Create one!</a></p>
    @endif
@endsection

Output:

TEXT
// Execution Successful

5. Blade Component

(1) Anonymous Components

HTML
<!-- resources/views/components/shop-card.blade.php -->
@props(['shop', 'highlight' => false])

<div class="card {{ $highlight ? 'border-gold' : '' }}">
    <h3>{{ $shop->name }}</h3>
    <p>{{ $shop->description }}</p>
    {{ $slot }}
</div>

<!-- Usage -->
<x-shop-card :shop="$shop" :highlight="true">
    <p>Featured this week!</p>
</x-shop-card>

(2) Class Components

BASH
php artisan make:component Alert
# Creates: app/View/Components/Alert.php
# And:     resources/views/components/alert.blade.php
PHP
// app/View/Components/Alert.php
class Alert extends Component
{
    public function __construct(
        public string $type = 'info',
        public ?string $message = null,
    ) {}

    public function render(): View
    {
        return view('components.alert');
    }
}
HTML
<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
    {{ $message ?? $slot }}
</div>

<!-- Usage -->
<x-alert type="success" message="Shop created!" />
<x-alert type="warning">Check your settings.</x-alert>
Dimension Anonymous Class
File Blade Templates Only PHP Classes + Blade Templates
Logic None/Minimal May include business logic
Props @props() Declaration Constructor Parameters
Suitable for Simple display components Components requiring logic

(1) ▶ Example: ShopMetrics Statistics Card Component

HTML
<!-- resources/views/components/stat-card.blade.php -->
@props(['label', 'value', 'icon', 'trend' => null])

<div class="bg-white rounded-lg shadow p-6">
    <div class="flex items-center justify-between">
        <div>
            <p class="text-gray-500 text-sm">{{ $label }}</p>
            <p class="text-2xl font-bold">{{ $value }}</p>
            @if($trend)
                <p class="text-sm {{ $trend > 0 ? 'text-green-500' : 'text-red-500' }}">
                    {{ $trend > 0 ? '+' : '' }}{{ $trend }}%
                </p>
            @endif
        </div>
        <span class="text-3xl">{{ $icon }}</span>
    </div>
</div>

<!-- Usage in dashboard -->
<x-stat-card label="Total Revenue" value="$12,450" icon="$" :trend="15.3" />
<x-stat-card label="Active Shops" value="23" icon="#" :trend="-2.1" />

Output:

TEXT
// Execution Successful

6. View Composer

View Composers automatically inject shared data into views, eliminating the need to pass it repeatedly in each controller method.

PHP
// app/Providers/AppServiceProvider.php
public function boot(): void
{
    // Share tenant info with all dashboard views
    View::composer('dashboard.*', function ($view) {
        $view->with('tenant', Tenant::current());
    });

    // Share navigation data with specific views
    View::composer(['layouts.app', 'shops.*'], NavigationComposer::class);
}
Type When to Execute Purpose
View::composer() Each time the view is rendered Dynamically calculate data
View::creator() When instantiating a view Bind data earlier
View::share() All Views Global Constants

(1) ▶ Example: ShopMetrics Navigation View Composer

PHP
// app/View/Composers/NavigationComposer.php
class NavigationComposer
{
    public function compose(View $view): void
    {
        $view->with([
            'navShops' => auth()->check()
                ? auth()->user()->shops()->take(5)->get()
                : collect(),
            'navNotifications' => auth()->check()
                ? auth()->user()->unreadNotifications()->count()
                : 0,
        ]);
    }
}

// Register in AppServiceProvider
View::composer('layouts.app', NavigationComposer::class);

Output:

TEXT
// Execution Successful

7. Front-End Assets: Vite

Laravel 11 uses Vite by default to compile front-end assets.

(1) Install Tailwind CSS and Alpine.js

BASH
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
npm install alpinejs

(2) Configure Vite

JAVASCRIPT
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
});

(3) Introduction to Blade

HTML
<!-- In layout head -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
Command Function
npm run dev Start the Vite development server (hot reload)
npm run build Compile Production Assets (Compressed)

(1) ▶ Example: ShopMetrics Navigation with Alpine.js Interactions

HTML
<!-- resources/views/partials/navbar.blade.php -->
<nav class="bg-white shadow" x-data="{ open: false }">
    <div class="container mx-auto px-4">
        <div class="flex justify-between h-16">
            <a href="{{ route('home') }}" class="font-bold text-xl">ShopMetrics</a>

            <div class="flex items-center">
                @auth
                    <div class="relative" @click="open = !open">
                        <button class="flex items-center">
                            {{ auth()->user()->name }}
                            @if($navNotifications > 0)
                                <span class="badge-red">{{ $navNotifications }}</span>
                            @endif
                        </button>
                        <div x-show="open" x-transition class="dropdown">
                            <a href="{{ route('dashboard') }}">Dashboard</a>
                            <a href="{{ route('shops.index') }}">Shops</a>
                            <form action="{{ route('logout') }}" method="POST">
                                @csrf
                                <button type="submit">Logout</button>
                            </form>
                        </div>
                    </div>
                @else
                    <a href="{{ route('login') }}">Login</a>
                @endauth
            </div>
        </div>
    </div>
</nav>

Output:

TEXT
// Execution Successful

8. Comprehensive Example: ShopMetrics Dashboard Page

HTML
<!-- ============================================
     Comprehensive: ShopMetrics Dashboard Page
     Covers: layout inheritance, components, directives, Alpine.js
     ============================================ -->

<!-- resources/views/dashboard/index.blade.php -->
@extends('layouts.dashboard')

@section('title', 'Dashboard — ShopMetrics')

@section('dashboard-content')
    <div class="space-y-6" x-data="{ period: '7d' }">
        <!-- Period Selector -->
        <div class="flex gap-2">
            <button @click="period = '7d'"
                    :class="period === '7d' ? 'btn-primary' : 'btn-secondary'">7 Days</button>
            <button @click="period = '30d'"
                    :class="period === '30d' ? 'btn-primary' : 'btn-secondary'">30 Days</button>
            <button @click="period = '90d'"
                    :class="period === '90d' ? 'btn-primary' : 'btn-secondary'">90 Days</button>
        </div>

        <!-- Stat Cards -->
        <div class="grid grid-cols-4 gap-4">
            <x-stat-card label="Total Revenue" value="${{ number_format($totalRevenue, 0) }}" icon="$" :trend="$revenueTrend" />
            <x-stat-card label="Orders" value="{{ number_format($orderCount) }}" icon="#" :trend="$orderTrend" />
            <x-stat-card label="Active Shops" value="{{ $activeShops }}" icon="#" :trend="$shopTrend" />
            <x-stat-card label="Conversion Rate" value="{{ number_format($conversionRate, 1) }}%" icon="%" :trend="$conversionTrend" />
        </div>

        <!-- Recent Orders -->
        <div class="bg-white rounded-lg shadow">
            <h2 class="p-4 border-b font-semibold">Recent Orders</h2>
            @forelse($recentOrders as $order)
                <div class="p-4 border-b flex justify-between">
                    <span>{{ $order->product_name }}</span>
                    <span>${{ number_format($order->total, 2) }}</span>
                </div>
            @empty
                <p class="p-4 text-gray-500">No orders in this period.</p>
            @endforelse
        </div>
    </div>
@endsection

❓ FAQ

Q What is the difference between {{ }} and {!! !!} in Blade?
A {{ }} automatically escapes HTML (to prevent XSS), while {!! !!} outputs raw HTML without escaping. Use {!! !!} only when the content is trusted, such as output from a rich-text editor.
Q What is the difference between @include and @component?
A @include is used for simply including view snippets without prop isolation; @component has explicit prop declarations and a slot mechanism, making it more suitable for reusable UI components. Use @include for simple snippets and @component for standalone components.
Q What is the difference between Blade components and Vue components?
A Blade components are rendered on the server and generate static HTML; Vue components are rendered on the client and support reactive data binding. In Laravel projects, Blade is typically used for page structure, while Alpine.js or Vue is used for interactivity.
Q What is the difference between Vite and Mix?
A Vite is the default frontend build tool for Laravel 9 and later; it uses an ES Module development server, which starts up quickly and supports hot reloading. Mix (Laravel Mix) is based on Webpack; it's easy to configure but slower. Use Vite for new projects.
Q How do I debug variables in Blade?
A Use {{ dd($variable) }} to dump and pause the page directly; or install the Laravel Debugbar extension to view all variables, SQL queries, and memory usage.
Q What is the difference between how View Composers and Controllers pass data?
A Controllers explicitly pass data using view('xxx', ['key' => $value]), which is suitable for data specific to that view; View Composers automatically inject shared data, which is suitable for data needed by multiple views (such as the navigation bar or the number of notifications).

📖 Summary


📝 Exercises

  1. Basic Exercise (⭐): Create a layouts/app.blade.php layout file for ShopMetrics that includes a navigation bar and footer, then create a homepage home/index.blade.php that inherits from this layout and populate it with content.

  2. Advanced Exercise (⭐⭐): Create a <x-alert> Blade component that supports a type (success/warning/error) and slot content, to be used in ShopMetrics scenarios where creation is successful or validation fails.

  3. Challenge (⭐⭐⭐): Use Alpine.js to implement a collapsible sidebar component, integrate it into a dashboard layout, support automatic collapse on mobile devices, and save the state to localStorage.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏