前言
ThinkPHP 模板引擎提供豐富的靜態資源引入標籤與流程控制標籤,但開發者常混淆 <import>、<load>、原生標籤的差異,以及分支結構的運算子對照。本文系統整理四種引入方式、路徑解析規則、條件/循環標籤語法、運算子對照表與最佳實踐。
一、CSS/JS 引入四大方式對比
| 方式 | 語法 | 輸出範例 | 適用場景 | 優缺點 |
| 原生 HTML | <link href="__PUBLIC__/Css/app.css"> | 原生標籤 | CDN、非標準路徑、完全控制 | +直觀 -需手動維護變量 |
| <import> | <import type="css" file="Css.app" /> | <link href="/Public/Css/app.css"> | 標準 Public 目錄結構、模組化專案 | +簡潔自動路徑 -依賴目錄慣例 |
| <load> | <load href="__PUBLIC__/Js/app.js" /> | 自動判斷生成 link/script | 混合路徑、快速原型 | +自動偵測類型 -部分版本棄用 |
| 助手函數 | {:css('app')} / {:js('app')} | 可擴展版本號、CDN、壓縮 | 現代專案 (TP5/6/8 推薦) | +功能強 -需自行封裝 |
二、<import> 深度用法
<!-- 基礎:Public 目錄下 -->
<import type="css" file="Css.common" /> <!-- /Public/Css/common.css -->
<import type="js" file="Js.jquery" /> <!-- /Public/Js/jquery.js -->
<!-- 跨模組:模組名.目錄.檔案 -->
<import type="css" file="Admin.Css.dashboard" /> <!-- /Public/Admin/Css/dashboard.css -->
<!-- basepath 突破 Public 限制 (CDN/外部儲存桶) -->
<import type="css" file="bootstrap.min" basepath="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css" />
<import type="js" file="app.min" basepath="https://bucket.oss-cn-hangzhou.aliyuncs.com/assets/js" />
<!-- 主題支援 (需配置 THEME_NAME) -->
<import type="css" file="Css.theme" theme="mobile" />
<!-- 解析為: /Public/mobile/Css/theme.css -->
三、<load> 自動偵測 (ThinkPHP 3.x 主流,5.x+ 漸棄用)
<load href="__PUBLIC__/Css/app.css" /> <!-- 生成 <link rel="stylesheet" href="..."> -->
<load href="__PUBLIC__/Js/app.js" /> <!-- 生成 <script src="..."></script> -->
<load href="https://cdn.example.com/lib.js" /> <!-- 外部絕對 URL -->
<load href="/custom/path/style.less" /> <!-- 非標準副檔名視為 CSS -->
四、模板分支結構:if / elseif / else
運算子對照表 (ThinkPHP 模板專用,區分大小寫)
| PHP 運算子 | 模板運算子 | 範例 |
== / === | eq / heq | <if condition="$a eq $b"> |
!= / !== | neq / nheq | <if condition="$a neq $b"> |
> | gt | <if condition="$a gt $b"> |
>= | egt | <if condition="$a egt $b"> |
< | lt | <if condition="$a lt $b"> |
<= | elt | |
% (取模) | mod | <if condition="$a mod 2 eq 0"> |
in | in | <if condition="$a in [1,2,3]"> |
not in | notin | <if condition="$a notin [1,2,3]"> |
=== (型別+值) | heq | <if condition="$a heq $b"> |
!== | nheq | <if condition="$a nheq $b"> |
基礎語法
<if condition="$user.vip eq 1">
<span class="badge vip">VIP</span>
<elseif condition="$user.level gt 5" />
<span class="badge senior">資深用戶</span>
<else />
<span class="badge normal">普通用戶</span>
</if>
<!-- 巢狀 -->
<if condition="$status eq 1">
<if condition="$type eq 'vip'">VIP 正常<else />普通正常</if>
<elseif condition="$status eq 0" />
已禁用
<else />
未知狀態
</if>
進階:present / notpresent / empty / notempty
<!-- present: 變量存在且非空 (對應 isset() && !empty()) -->
<present name="user.avatar">
<img src="{$user.avatar}" />
<else />
<img src="__PUBLIC__/Images/default_avatar.png" />
</present>
<!-- empty: 變量不存在或為空 -->
<empty name="list">
<p>暫無數據</p>
</empty>
五、Switch 分支結構
<switch name="order.status">
<case value="0">待付款</case>
<case value="1">已付款</case>
<case value="2">已發貨</case>
<case value="3">已完成</case>
<case value="4">已退款</case>
<default />未知狀態
</switch>
<!-- 多值匹配 (ThinkPHP 5/6/8 支援) -->
<switch name="user.role">
<case value="admin,superadmin">管理員</case>
<case value="editor,author">編輯</case>
<default />普通用戶
</switch>
六、循環結構:volist / foreach
<!-- volist: 專為陣列/集合設計,支援模板變量輸出 -->
<volist name="list" id="vo" key="k" offset="0" length="10">
<tr>
<td>{$k}</td>
<td>{$vo.name}</td>
<td>{$vo.price|number_format=2}</td>
<td>
<if condition="$vo.status eq 1">上架<else />下架</if>
</td>
</tr>
</volist>
<!-- foreach: 簡化語法 (ThinkPHP 5/6/8) -->
<foreach name="list" item="vo">
{$vo.name} - {$vo.price}
</foreach>
<!-- 迴圈變量 (volist) -->
<volist name="list" id="vo">
{$vo.iteration} // 當前迴圈次數 (從 1 開始)
{$vo.first} // 是否第一次
{$vo.last} // 是否最後一次
{$vo.index} // 當前索引 (從 0 開始)
{$vo.key} // 當前鍵名
{$vo.mod2} // 當前次數 % 2 (用於斑馬紋)
{$vo.mod3} // 當前次數 % 3
</volist>
七、最佳實踐與避坑指南
- 統一引入方式:專案規範只用助手函數
css()/js() 或 <import>,禁用原生標籤硬編碼路徑。
- 大小寫敏感:Linux 伺服器
file="Css.App" 找不到 Public/Css/app.css,統一小寫檔案名與引用。
- 運算子必須小寫:
EQ、GT 會報錯,只能用 eq、gt。
- 變量輸出預設 HTML 轉義:
{$var} 自動 htmlspecialchars,需原樣輸出用 {$var|raw}。
- 避免在模板中寫複雜邏輯:複雜判斷移至控制器或視圖模型 (View Model),模板只做簡單分支/迴圈。
- 模板繼承優於 include:使用
<extend name="layout" /> + <block name="content"> 替代大量 <include>,結構更清晰。
八、ThinkPHP 5/6/8 現代語法對照
| TP 3.x 標籤 | TP 5/6/8 原生 PHP | 備註 |
<if condition="$a eq $b"> | <?php if ($a == $b): ?> | 推薦原生 PHP,IDE 支援完整 |
<volist name="list" id="vo"> | <?php foreach ($list as $vo): ?> | 原生 foreach 功能更強 |
<import type="css" file="Css.app"> | {:css('app')} | 助手函數更靈活 |
<extend name="layout"> | <?php $this->extend('layout') ?> | 配合 block 實現繼承 |
{$var|function=arg} | <?php echo function($var, 'arg'); ?> | 原生調用任意函數 |
結語
ThinkPHP 模板引擎的引入標籤與分支結構雖然功能豐富,但隨著版本演進,現代專案強烈建議遷移至原生 PHP 模板 + 助手函數封裝。若維護 TP 3.x 舊專案,掌握 <import>/<load> 路徑解析、模板運算子對照、volist 迴圈變量、present/empty 判斷等核心知識點,即可高效開發與維護。關鍵原則:**路徑變量化、邏輯控制器化、輸出轉義化、結構繼承化**。