首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP volist 標簽嵌套循環完整教程:從控制器構建到模板輸出

     編輯:PHP 相關知識

ThinkPHP volist 標簽嵌套循環完整教程:從控制器構建到模板輸出

ThinkPHP 模板引擎的 volist 標簽支持多層嵌套,是輸出樹形結構、分類關聯數據的核心工具。本文通過「分類-報價」實戰案例,完整演示控制器數據構建、模板嵌套寫法、嵌套層級限制配置、常見錯誤排查。

一、官方語法規範

<volist name="list" id="vo">
    <volist name="vo['sub']" id="sub">
        {$sub.name}
    </volist>
</volist>
  • name:數據源變量 (模板變量名或嵌套鍵路徑)
  • id:循環變量名 (當前項)
  • 默認最大嵌套 3 層,超過需配置 TAG_NESTED_LEVEL

二、數據庫表結構

-- 分類表
CREATE TABLE category (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    listorder INT DEFAULT 0
);

-- 報價表
CREATE TABLE quote (
    id INT PRIMARY KEY AUTO_INCREMENT,
    cate_id INT NOT NULL COMMENT '關聯分類ID',
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2)
);

三、控制器構建二維關聯數組 (核心步驟)

<?php
namespace Home\Controller;
use Think\Controller;

class IndexController extends Controller {
    public function index() {
        $Quote = M('Quote');
        $Category = M('Category');
        
        // 1. 查詢所有分類 (父級數據)
        $categories = $Category->order('listorder')->select();
        
        // 2. 遍歷分類,查詢各分類下的報價,掛載為 'voo' 子數組
        foreach ($categories as $key => $cate) {
            $categories[$key]['voo'] = $Quote->where(['cate_id' => $cate['id']])->select();
        }
        
        // 3. 賦值到模板
        $this->assign('list', $categories);
        $this->display();
    }
}
?>

關鍵點:

  • 外層 volist 遍歷 $list (即 $categories)
  • 內層 volist 遍歷 vo['voo'] (控制器掛載的子數組鍵名)
  • 鍵名 voo 可自定義,但控制器與模板必須一致

四、模板文件嵌套輸出

<!-- 分類列表頁 -->
<volist name="list" id="vo">
    <div class="category-item">
        <h3>{$vo.name}</h3>
        
        <!-- 內層遍歷該分類下的報價 -->
        <volist name="vo['voo']" id="sub">
            <div class="quote-item">
                <span class="name">{$sub.name}</span>
                <span class="price">¥{$sub.price}</span>
            </div>
        </volist>
    </div>
</volist>

五、輸出效果示例

分類:手機
  報價:iPhone 15 Pro - ¥7999
  報價:小米 14 Ultra - ¥5999

分類:筆記本
  報價:MacBook Pro M3 - ¥14999
  報價:ThinkPad X1 Carbon - ¥12999

六、進階:三層以上嵌套 (國家-省-市-區)

1. 配置嵌套層級

// config.php 或模板引擎配置
'TAG_NESTED_LEVEL' => 5, // 支持 5 層嵌套

2. 控制器構建三維數組

$countries = M('Country')->select();
foreach ($countries as $i => $country) {
    $provinces = M('Province')->where(['country_id' => $country['id']])->select();
    foreach ($provinces as $j => $province) {
        $provinces[$j]['cities'] = M('City')->where(['province_id' => $province['id']])->select();
    }
    $countries[$i]['provinces'] = $provinces;
}
$this->assign('list', $countries);

3. 模板三層嵌套

<volist name="list" id="country">
    {$country.name}
    <volist name="country['provinces']" id="province">
        {$province.name}
        <volist name="province['cities']" id="city">
            {$city.name}
        </volist>
    </volist>
</volist>

七、性能優化:避免 N+1 查詢

上述示例中,foreach 循環查詢會產生 1 + N 條 SQL (N=分類數)。大數據量時優化方案:

方案 A:單次聯表查詢 + PHP 重組 (推薦)

$data = M('Category')
    ->join('LEFT JOIN quote ON category.id = quote.cate_id')
    ->field('category.id, category.name, quote.id as qid, quote.name as qname, quote.price')
    ->order('category.listorder, category.id')
    ->select();

// PHP 重組為樹形
$tree = [];
foreach ($data as $row) {
    $cid = $row['id'];
    if (!isset($tree[$cid])) {
        $tree[$cid] = ['id' => $cid, 'name' => $row['name'], 'voo' => []];
    }
    if ($row['qid']) {
        $tree[$cid]['voo'][] = ['id' => $row['qid'], 'name' => $row['qname'], 'price' => $row['price']];
    }
}
$this->assign('list', array_values($tree));

方案 B:分兩次查詢 + PHP 映射 (適合極大數據)

$categories = M('Category')->select();
$quotes = M('Quote')->select();
$quoteMap = [];
foreach ($quotes as $q) {
    $quoteMap[$q['cate_id']][] = $q;
}
foreach ($categories as &$cate) {
    $cate['voo'] = $quoteMap[$cate['id']] ?? [];
}
$this->assign('list', $categories);

八、常見錯誤與排查

錯誤現象原因解決
內層不輸出 / 空白鍵名不匹配:控制器用 voo,模板寫 vo['sub']統一鍵名,或模板改為 vo['voo']
嵌套超過 3 層報錯默認 TAG_NESTED_LEVEL=3配置文件設置 'TAG_NESTED_LEVEL' => 5
變量衝突 / 顯示錯亂內外層 id 變量名相同內層用不同 id:id="sub"、id="city"
在嵌套中使用 <form> 出錯HTML 不允許 <form> 嵌套調整結構:每行一個 form、或用 AJAX 提交
數據量大頁面極慢N+1 查詢、未優化使用方案 A/B 優化為 1-2 條 SQL

九、volist 進階屬性

<volist name="list" id="vo" key="k" mod="3" empty="暫無數據">
    
    
    <div class="item-{$vo.id} row-{$k % 3}">{$vo.name}</div>
</volist>
  • key:索引變量名 (默認 key)
  • mod:取模數,配合 $key % mod 實現隔行換色
  • empty:數據為空時顯示內容
  • offset / length:截取片段

十、總結

  1. 控制器:查詢父級 → 遍歷掛載子數組 (鍵名自定) → assign('list', $data)
  2. 模板:外層 volist name="list" → 內層 volist name="vo['子鍵名']"
  3. 嵌套超 3 層 → 配置 TAG_NESTED_LEVEL
  4. 大數據 → 單次聯表或分兩次查詢 + PHP 重組,消除 N+1
  5. 善用 key、mod、empty 提升模板表達力
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved