ThinkPHP 2.x 模板引擎的 <volist> 標籤提供 mod 屬性配合 $mod 變數實現「每 N 筆換行」功能。但官方手冊範例在第一行會少輸出一筆資料(如 mod=5,第一行僅 4 筆),導致版面錯亂。本文解析核心原始碼,給出精確修正位置與替代寫法。
<volist name="list" id="vo" mod="5">
{$vo.name}
<eq name="mod" value="4"><br/></eq>
</volist>
預期: 每 5 筆換行(索引 0-4,第 4 筆後換行)。
實際: 第一行輸出 4 筆(索引 0-3),第二行起才正常 5 筆。
檔案:ThinkPHP/Lib/Think/Template/TagLib/TagLibCx.class.php(約第 107-108 行)
// 原始碼(有 Bug)
$parseStr .= '++$'.$key.';'; // 先遞增索引
$parseStr .= '$mod = ($'.$key.' % '.$mod.' )?>'; // 再計算 mod
邏輯錯誤: 迴圈開始時 $key=0,先 ++$key 變 1,再 1 % 5 = 1,導致第一筆 $mod=1,而非預期的 0。第 5 筆時 $key=5,5%5=0,判斷 value="4" 失效,故第一行少一筆。
// 修正後
$parseStr .= '$mod = ($'.$key.' % '.$mod.' );'; // 先計算 mod(基於當前索引)
$parseStr .= '++$'.$key.'?>'; // 再遞增索引供下輪
修正後:
第 1 筆:$key=0 → $mod=0%5=0 → ++$key=1
第 5 筆:$key=4 → $mod=4%5=4 → 滿足 value="4" 換行 → ++$key=5
完全符合預期。
利用 key 屬性自訂索引變數,配合 neq 避免最後多餘換行:
<volist name="list" id="vo" key="k" mod="5">
{$vo.title}<br/>
<eq name="mod" value="4">
<neq name="k" value="$count"><br /></neq>
</eq>
</volist>
key="k":索引從 1 開始($k=1,2,3...)mod="5":$mod = ($k % 5) → 1,2,3,4,0 循環value="4":第 4 筆($mod=4)換行neq name="k" value="$count":最後一筆不換行<volist name="list" id="vo">
{$i} - {$vo.name} // 預設 $i 從 1 開始
</volist>
<volist name="list" id="vo" key="idx">
{$idx} - {$vo.name} // 自訂變數 $idx
</volist>
{:foreach} 或 volist 但內部邏輯已重寫,無此問題。總結: Bug 成因是模板編譯階段「遞增索引」與「計算 mod」順序顛倒。修正核心檔只需交換兩行;若不想動核心,使用 key+mod+neq 組合更靈活且升級無憂。