Blade 模板是藝術品還是災難現場?Laravel 資深工程師的 8 個關鍵實踐,打造可維護、高效能的視圖架構

2025/12/3 | Laravel技術分享, 全端與程式開發, 技術教學資源

告別義大利麵:Laravel Blade 視圖架構最佳實務

您的 Blade 模板是高效能架構還是技術債炸彈?資深工程師 Eric 揭示 8 個關鍵實踐,助您徹底落實 MVC 關注點分離。請立即停止在視圖中濫用複雜的 @php 邏輯,並開始擁抱 Blade Components 取代混亂的 @include,以建立可重複使用、語意清晰的 UI 單元。學會善用 View Composers 進行高效資料注入,讓您的視圖層乾淨、優雅且易於維護!別再讓 View 拖垮專案健康度,立即升級您的開發實踐,打造堅實的軟體基石。

需要專業協助?

聯絡浪花專案團隊 →

你的 Blade 模板是藝術品還是災難現場?Laravel 資深工程師的 8 個關鍵實踐,打造可維護、高效能的視圖架構

嗨,我是浪花科技的 Eric。身為一個在 WordPress 和 Laravel 兩個世界穿梭的工程師,我看過太多令人讚嘆的程式碼,當然,也見過不少讓人血壓飆升的「義大利麵式」程式碼。尤其是在視圖層(View Layer),這裡常常是技術債的重災區。很多開發者覺得「啊,不就是輸出 HTML 嘛,能動就好」,結果就是 Controller 肥大、View 裡面塞滿商業邏輯,三個月後回來看,連自己都想打自己。

別鬧了,一個好的專案,從後端架構到前端模板都應該是清晰、優雅且高效的。今天,我們不談 WordPress 的 a-actions 和 f-filters,來聊聊隔壁棚 Laravel 的 Blade 模板引擎。Blade 的簡潔語法底下,其實蘊含著深刻的軟體架構思維。這篇文章不是要給你一堆複製貼上的程式碼片段,而是要帶你從架構層面,徹底搞懂 Laravel Blade 模板最佳實務,讓你的視圖層不再是專案的負擔,而是堅實的基石。

一、停止在 Blade 中濫用 @php:視圖的唯一職責是「呈現」

這是我最想囉嗦的一點,也是新手最常犯的錯。看到 @php 就手癢,想在 Blade 裡面做一堆資料處理、邏輯判斷,甚至…下資料庫查詢?拜託,快住手!

MVC 架構的核心精神就是「關注點分離」(Separation of Concerns)。

  • Model: 處理資料與商業邏輯。
  • View: 負責呈現資料,越笨越好。
  • Controller: 扮演兩者之間的橋樑,調度 Model 準備好資料,再餵給 View。

當你在 Blade 裡寫下複雜的邏輯,你等於是打破了這個原則。這會導致:

  • 難以測試: 你要怎麼對 Blade 裡的邏輯寫單元測試?幾乎不可能。
  • 難以維護: 商業邏輯散落在 Controller 和 View 各處,尋找和修改都像在尋寶,而且是那種會爆炸的寶藏。
  • 效能問題: 在 View 裡面執行非預期的資料庫查詢,很容易造成 N+1 問題,拖垮整個頁面效能。

工程師小囉嗦: 你的 Blade 應該要「笨」到只會做簡單的 if/elseforeach 迴圈,以及顯示從 Controller 傳過來的變數。所有資料的整理、計算、篩選,都應該在 Controller 或更下層的 Service/Repository 完成。把乾淨、準備好的資料「盤子」端給 Blade,它只需要負責把菜擺上桌就好。

反面教材:

<!-- 這會讓未來的你很痛苦 -->
@php
    $activeUsers = App\Models\User::where('status', 'active')->where('last_login_at', '>', now()->subDays(30))->get();
    $premiumCount = 0;
    foreach($activeUsers as $user) {
        if ($user->isPremium()) {
            $premiumCount++;
        }
    }
@endphp

<p>活躍的白金會員數:{{ $premiumCount }}</p>

最佳實踐:

<!-- 在 Controller 中準備好資料 -->
// In YourController.php
public function showDashboard()
{
    $premiumCount = $this->userService->getActivePremiumCount();
    return view('dashboard', ['premiumCount' => $premiumCount]);
}

<!-- 在 Blade 中,只做呈現 -->
<!-- dashboard.blade.php -->
<p>活躍的白金會員數:{{ $premiumCount }}</p>

二、擁抱組件化 (Components):告別 @include 義大利麵

當你的專案開始變大,你會發現很多 UI 元素(按鈕、卡片、表單輸入框)不斷重複出現。很多人的直覺是使用 @include。這在初期是可行的,但當你需要傳遞一堆變數,而且巢狀結構越來越深時,很快就會變成一場災難。

Laravel 的 Blade 組件 (Components) 是解決這個問題的利器。它讓你可以像使用 Vue 或 React 組件一樣,建立可重複使用、自給自足的 UI 單元。每個組件都有自己的 Class 處理邏輯,和自己的 Blade 檔案處理樣式。

為什麼組件優於 @include?

  • 語意清晰: <x-forms.button type="primary">送出</x-forms.button> 遠比 @include('partials.button', ['type' => 'primary', 'text' => '送出']) 來得直觀。
  • 邏輯封裝: 你可以在組件的 Class 中處理複雜的顯示邏輯(例如,根據不同狀態顯示不同顏色或 icon),讓 Blade 檔案保持乾淨。
  • 資料隔離: 組件只接收明確傳入的 props,不會意外地污染或被外部變數影響。
  • 插槽 (Slots): 組件提供了強大的 $slot 功能,讓你可以輕鬆地將內容嵌入到組件的預定位置,增加了極大的彈性。

想像一下,一個 Modal 彈窗組件,你可以這樣優雅地使用它:

<x-modal title="確認刪除">
    <x-slot name="body">
        <p>你確定要刪除這筆資料嗎?此操作無法復原。</p>
    </x-slot>

    <x-slot name="footer">
        <x-forms.button type="secondary">取消</x-forms.button>
        <x-forms.button type="danger">確認刪除</x-forms.button>
    </x-slot>
</x-modal>

工程師小囉嗦: 這就像是在組裝一台電腦。你不會把 CPU、記憶體、硬碟的針腳全部焊死在主機板上(@include 的極端比喻)。你會使用標準化的插槽,讓每個零件(組件)都可以獨立運作、輕鬆替換。從今天起,把「建立可複用的 UI」這個念頭,從 @include 轉換到 Blade Components 吧!

三、善用 @inject 和 View Composers 注入依賴

有時候,某些資料在很多頁面都會用到,例如頁首的導覽列、頁尾的網站資訊、側邊欄的最新文章等。你總不希望在每個 Controller 的每個方法裡都去重複查詢這些資料吧?

這時候,你有兩個好幫手:

1. 視圖合成器 (View Composers)

View Composers 就像是針對特定 Blade 模板的「幕後工作人員」。你可以在 Service Provider 中註冊一個 Composer,告訴 Laravel:「嘿,當任何地方要渲染 `layouts.header` 這個模板時,請先執行這段程式碼,並把結果綁定到模板上。」

// In a ServiceProvider, e.g., AppServiceProvider.php
use Illuminate\Support\Facades\View;

public function boot()
{
    View::composer('layouts.header', function ($view) {
        $categories = Category::where('is_active', true)->get();
        $view->with('categories', $categories);
    });
}

這樣一來,所有使用 `layouts.header` 的地方,都會自動獲得 $categories 這個變數,完全不需要 Controller 的介入。

2. @inject 指令

如果你只是在單一模板中需要用到某個 Service 的方法,而且這個需求不具備全域性,@inject 是一個更輕量的選擇。它允許你直接在 Blade 模板的開頭,從 Laravel 的服務容器 (Service Container) 中解析出一個實例。

@inject('metrics', 'App\Services\MetricsService')

<div>
    今日訪客數: {{ $metrics->getTodayVisitors() }}
</div>

工程師小囉嗦: 兩者怎麼選?我的原則是:如果資料是跨越多個頁面的「共享佈局」元件(如頁首、頁尾),用 View Composer;如果只是某個特定頁面或大型組件需要呼叫一些輔助方法,用 @inject。但切記,別在 @inject 進來的 Service 方法裡做太複雜的商業邏輯,那應該是 Controller 的工作。

四、其他關鍵實踐,讓你的 Blade 更上一層樓

  • @once@push 當你有一個組件需要在頁面中多次使用,但它依賴的 JS 或 CSS 只需要載入一次時,@once 指令是你的救星。搭配 @push,可以將組件的資源集中推送到主佈局的特定堆疊 (stack) 中,避免重複載入。
  • @props 在組件的 Blade 檔案中,使用 @props 明確定義你期望接收的屬性,可以設定預設值,並將其餘屬性合併到 HTML 標籤上,非常方便。
  • 保持安全性: 永遠優先使用 {{ $variable }} 語法,Blade 會自動對內容進行 HTML 編碼,防止 XSS 攻擊。只有在你 100% 確定內容來源安全(例如,來自後台富文本編輯器且經過處理的內容)時,才謹慎使用 {!! $variable !!}
  • 利用迴圈變數 $loop@foreach 迴圈中,善用 Blade 自動提供的 $loop 變數,你可以輕易判斷是否為第一次/最後一次迭代 ($loop->first, $loop->last),取得索引 ($loop->index) 等,不需要自己再額外設定計數器。

寫出好的 Blade 模板,不只關乎程式碼的美觀,它直接影響到整個專案的健康度、可維護性和團隊協作效率。當你的視圖層清晰、模組化且職責單一時,你會發現新增功能、修改設計都變得輕而易舉。別再把 Blade 當成一個只能放 HTML 的地方了,把它當成你精心設計的應用程式架構中,優雅的最後一哩路吧!

延伸閱讀

如果你正在為你的 Laravel 或 WordPress 專案的架構感到頭痛,或是希望能導入更現代、更高效的開發實踐,浪花科技的團隊擁有豐富的實戰經驗,能幫助你從源頭打造穩固、可擴展的數位產品。我們不只是寫程式,我們打造能為你創造價值的系統。

準備好讓你的專案脫胎換骨了嗎?

👉 立即聯繫浪花科技,讓我們聊聊如何將你的想法,打造成兼具效能與優雅架構的成功專案!

常見問題 (FAQ)

Q1: 為什麼我應該避免在 Blade 模板中撰寫複雜的 PHP 邏輯?

最主要的原因是「關注點分離」。將商業邏輯放在 Blade 中會讓程式碼難以測試、維護和除錯。理想情況下,所有資料處理和業務邏輯都應在 Controller 或更下層的 Service/Repository 中完成,Blade 模板只負責「呈現」已經準備好的資料,保持其模板的單純性。

Q2: Blade 組件 (Components) 和 `@include` 有什麼核心區別?我該如何選擇?

@include 適合用來引入靜態或簡單的局部模板。而 Blade 組件則是一種更強大、更結構化的方法,它將模板(View)和邏輯(Class)封裝在一起,像是一個獨立的 UI 單元。當你需要建立可重複使用、需要傳遞 props、且可能包含自身邏輯的 UI 元素(如按鈕、卡片、表單),請優先選擇組件。組件的語法更清晰,也更容易管理。

Q3: 什麼時候該使用 View Composers,什麼時候又該用 `@inject`?

如果某個資料需要在多個頁面的共享佈局(如頁首、頁尾、側邊欄)中出現,使用 View Composers 是最佳選擇,它能讓你集中管理這些共享資料的邏輯。如果只是某個特定的、非共享的模板需要用到某個服務類別的輔助方法,使用 @inject 會更輕量、直觀。

Q4: 使用 {!! !!} 語法輸出未經處理的內容真的那麼危險嗎?

是的,非常危險。{!! !!} 會直接輸出原始 HTML,如果這些內容包含惡意的 JavaScript(例如,來自使用者留言),就會造成跨網站指令碼(XSS)攻擊,可能導致使用者帳號被盜用或網站被竄改。除非你 100% 確定內容的來源是絕對安全的,並且經過了嚴格的過濾處理,否則都應該堅持使用 {{ }} 來確保安全。

 
立即諮詢,索取免費1年網站保固