
本文介绍如何通过 php 嵌套循环 + jquery 动态控制,将主分类与其所有子分类结构化渲染到 html 表格中,并支持点击「+」按钮展开/收起对应子分类列表。
在构建后台商品分类管理界面时,常需以清晰层级展示「一级分类 → 二级分类」关系。原代码存在多个关键问题:嵌套 foreach 逻辑错位(内层 $row 覆盖外层变量)、条件判断失效($row->cat_id == $row->cat_id 恒为真)、数据关联方式不合理(未按主分类分组子类),导致子分类无法正确归属。
✅ 正确的数据组织方式
首先应在 Model 层完成「主分类 + 其子分类」的一体化查询,避免前端硬编码关联逻辑:
// 在 Model 中新增方法(推荐)
public function fetch_categories_with_subcats() {
$this->db->select('c.*, sc.sub_id, sc.sub_cat, sc.cat_id as parent_cat_id');
$this->db->from('categories c');
$this->db->join('subcat sc', 'sc.cat_id = c.id', 'left'); // left join 确保无子类的主分类仍可见
$this->db->order_by('c.flag_no, sc.sflag_no');
$query = $this->db->get();
// 将结果按主分类 ID 分组,每个主分类对象携带 subCats 数组
$categories = [];
foreach ($query->result() as $row) {
$catId = $row->id;
if (!isset($categories[$catId])) {
$categories[$catId] = (array)$row;
$categories[$catId]['subCats'] = [];
}
if (!empty($row->sub_id)) {
$categories[$catId]['subCats'][] = $row;
}
}
return array_values($categories);
}控制器调用该方法即可获得结构化数据:
public function categories() {
$data['categories'] = $this->Pro_model->fetch_categories_with_subcats();
$this->load->view('admin-new/categories.php', $data);
}✅ 清晰的视图嵌套结构(HTML + PHP)
在 View 中使用两层 foreach:外层遍历主分类,内层遍历其 subCats 子数组:
本书是全面讲述PHP与MySQL的经典之作,书中不但全面介绍了两种技术的核心特性,还讲解了如何高效地结合这两种技术构建健壮的数据驱动的应用程序。本书涵盖了两种技术新版本中出现的最新特性,书中大量实际的示例和深入的分析均来自于作者在这方面多年的专业经验,可用于解决开发者在实际中所面临的各种挑战。
立即学习“PHP免费学习笔记(深入)”;
<table class="table gap">
<thead>
<tr>
<th>Flag No.</th>
<th>Name</th>
<th>On/Off</th>
<th>Actions</th>
<th>Toggle</th>
</tr>
</thead>
<tbody>
<?php if (!empty($categories)): ?>
<?php foreach ($categories as $cat): ?>
<!-- 主分类行 -->
<tr>
<td><?= htmlspecialchars($cat['flag_no'] ?? '') ?></td>
<td><strong><?= htmlspecialchars($cat['cat_name'] ?? '') ?></strong></td>
<td>
<label class="switch">
<input type="checkbox" <?= !empty($cat['status']) && $cat['status'] == 'on' ? 'checked' : '' ?>>
<span class="slider round"></span>
</label>
</td>
<td class="action-cats">
<a href="<?= site_url('Products/delete_cat/' . $cat['id']) ?>"
onclick="return confirm('Delete this category?')">
@@##@@" width="20"> Delete
</a>
<a href="<?= site_url('Products/edit_cat/' . $cat['id']) ?>">
@@##@@" width="20"> Edit
</a>
</td>
<td>
<a href="#" class="toggle" data-cat-id="<?= $cat['id'] ?>">+</a>
</td>
</tr>
<!-- 子分类嵌套表格(默认隐藏) -->
<tr class="sub-category-row">
<td colspan="5">
<table class="sub-table" id="cat-id-<?= $cat['id'] ?>" style="display:none; margin-left: 20px;">
<tbody>
<?php if (!empty($cat['subCats'])): ?>
<?php foreach ($cat['subCats'] as $sub): ?>
<tr>
<td><?= htmlspecialchars($sub->sub_cat) ?></td>
<td></td>
<td></td>
<td class="action-cats">
<a href="<?= site_url('Products/delete_sub_cat/' . $sub->sub_id) ?>"
onclick="return confirm('Delete this subcategory?')">
@@##@@" width="20"> Delete
</a>
<a href="<?= site_url('Products/edit_sub_cat/' . $sub->sub_id) ?>">
@@##@@" width="20"> Edit
</a>
</td>
<td></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="4"><em>No subcategories</em></td></tr>
<?php endif; ?>
</tbody>
</table>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="5">No categories found.</td></tr>
<?php endif; ?>
</tbody>
</table>✅ jQuery 实现动态展开/收起
添加轻量级脚本,绑定点击事件并切换对应子表格显示状态:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
$('.toggle').on('click', function(e) {
e.preventDefault();
const catId = $(this).data('cat-id');
const $subTable = $('#cat-id-' + catId);
$subTable.slideToggle(200);
$(this).text($subTable.is(':visible') ? '−' : '+');
});
});
</script>? 注意事项 使用 htmlspecialchars() 防止 XSS 攻击; 子表格 id 必须与 data-cat-id 严格匹配(如 cat-id-5 ↔ data-cat-id="5"); 推荐用 slideToggle() 提升交互体验,替代生硬的 toggle(); 若数据库中存在深层嵌套(三级+),建议改用递归组件或 Vue/React 渲染,PHP 嵌套不宜过深。
通过以上重构,你将获得语义清晰、可维护性强、用户体验良好的多级分类管理界面。
%20?><img%20src=)










