PHP生成数据库下拉菜单时子项<a>标签嵌套错误问题求助
问题描述
我的数据库中有menu表,结构包含name、slug、order、submenu、fk字段,数据包含主菜单与对应子项。我用以下SQL语句获取菜单列表:
$list = Sql->select('SELECT * FROM menu ORDER BY order, submenu DESC, name');
需要生成的带下拉的HTML菜单结构如下:
<UL> <li><a ...> menu 1 </a></li> <li><a ...> menu 2 </a></li> <li><a ...> menu 3 </a> <div> <a ...> sub3.1 </a> <a ...> sub3.2 </a> <a ...> sub3.3 </a> </div> </li> <li><a ...> menu 4 </a> <div> <a ...> sub4.1 </a> <a ...> sub4.2 </a> </div> </li> </UL>
我编写了如下PHP代码实现,但生成的子菜单<a>元素位于div.dropdown-menu标签外部,请问问题出在哪里?
现有PHP代码:
<UL><?php $is_prev_subitem = false; foreach($list as $menu){ $is_submenu = $menu['submenu']==1; $is_subitem = $menu['fk']>0; if($is_prev_subitem && !$is_subitem){ echo "</div></li>"; } if(!$is_subitem){ echo "<LI class='nav-item ".($is_submenu ? ' dropdown' : '')."'>"; } echo "<a href='#' class='nav-link ".($is_submenu ? ' dropdown-toggle' : '')."' id='{$menu['slug']}'> {$menu['name']} </a>"; if($is_submenu){ echo "<div class='dropdown-menu' aria-labelledby='{$menu['slug']}'>"; } if(!$is_subitem){ echo "</LI>"; } $is_prev_subitem = $is_subitem; } ?> </UL>
问题原因分析
- 主菜单闭合时机错误:当
!$is_subitem时立刻闭合<LI>,但如果这个主菜单是带下拉的(is_submenu=1),此时<div.dropdown-menu>刚打开就被<LI>闭合,后续的子项自然会跑到容器外面。 - 子项输出逻辑缺失:现有代码没有针对子项做特殊处理,子项的
<a>直接输出,没有依托已打开的dropdown-menu容器。 - 结束标签处理不完整:循环结束后未检查是否还有未闭合的
dropdown-menu和<LI>,会导致标签结构不完整。
修正后的代码
<UL><?php $is_prev_subitem = false; $current_dropdown_open = false; foreach($list as $menu){ $is_submenu = $menu['submenu'] == 1; $is_subitem = $menu['fk'] > 0; // 结束上一组子项:之前是子项、当前不是时,闭合下拉容器和主菜单LI if($is_prev_subitem && !$is_subitem){ echo "</div></li>"; $current_dropdown_open = false; } // 处理主菜单 if(!$is_subitem){ echo "<LI class='nav-item ".($is_submenu ? ' dropdown' : '')."'>"; // 输出主菜单链接 echo "<a href='#' class='nav-link ".($is_submenu ? ' dropdown-toggle' : '')."' id='{$menu['slug']}'> {$menu['name']} </a>"; // 打开下拉容器(如果是下拉菜单) if($is_submenu){ echo "<div class='dropdown-menu' aria-labelledby='{$menu['slug']}'>"; $current_dropdown_open = true; } else { // 非下拉菜单直接闭合LI echo "</LI>"; } } else { // 输出子项链接(自动落入已打开的下拉容器) echo "<a class='dropdown-item' href='#' id='{$menu['slug']}'>{$menu['name']}</a>"; } $is_prev_subitem = $is_subitem; } // 循环结束后收尾:闭合未关闭的下拉容器和LI if($current_dropdown_open){ echo "</div></li>"; } ?> </UL>
关键修正点
- 调整主菜单闭合逻辑:非下拉主菜单直接闭合
<LI>,下拉主菜单留到子项全部输出后再闭合。 - 明确子项输出位置:子项的
<a>直接输出在已打开的dropdown-menu容器内,确保结构嵌套正确。 - 增加循环收尾处理:避免最后一组下拉菜单因无后续主菜单导致标签未闭合的问题。
内容的提问来源于stack exchange,提问作者Thiago
相关产品推荐
相关产品推荐

