我正在尝试用php制作多级菜单,但我无法正确输出html。
首先,我从数据库中提取数据,在"sort_id"和"id"之后对其进行排序,并将其存储在数组中。
数据库结构:
id | parent_id | sort_id | title
---------------------------------
1 | 0 | 0 | test1
2 | 1 | 1 | test2
3 | 1 | 0 | test3
4 | 0 | 1 | test4
5 | 2 | 0 | test5
PHP代码
function hasChildren( $id, $data ) {
foreach ($data as $d ) {
if ( $d['parent_id'] == $id ) {
return true;
break;
}
}
}
function menu ($arr) {
foreach ( $arr as $d ) {
if( is_array($d) && $d['parent_id'] == 0 ) {
echo "<li><a href={$d['link']}>{$d['title']}</a>";
if ( hasChildren ($d['id'], $arr) ) echo "<ul>";
}
foreach ( $arr as $row ) {
if ( is_array($row) ) {
if( $row['parent_id'] == $d['id'] ) {
if ( hasChildren ($row['id'], $arr) ) {
echo "<li><a href={$row['link']}>{$row['title']}</a><ul>";
} else echo "<li><a href={$row['link']}>{$row['title']}</a>";
menu($row);
if ( hasChildren ($row['id'], $arr) ) {
echo "</ul></li>";
} else echo "</li>";
}
}
}
if ( is_array($d) && $d['parent_id'] == '0' ) {
if ( hasChildren ($d['id'], $arr) ) echo "</ul>";
echo "</li>";
}
}
}
网页输出
<li>
<a href="http://localhost">test1</a>
<ul>
<li><a href="http://localhost/2">test3</a></li>
<li><a href="http://localhost/1">test2</a>
<ul></ul>
</li>
</ul>
</li>
<li><a href="http://localhost/5">test5</a></li>
<li><a href="http://localhost/4">test4</a></li>
在"Test2"打开和关闭"UL"标签之后
"test5"应该是"test2"的子项,而不是父项
我知道这可能不是最好的方法,但任何人都可以告诉我我做错了什么?
1) menu($row); 是无用的,因为它什么都不做
2)如果要应用递归,必须这样写:
function menu($arr, $parent) {
$open = 0;
foreach ($arr as $row) {
if ($parent == $row['parent_id']) {
echo ($open?'':'<ul>')."<li><a href={$row['link']}>{$row['title']}</a>";
menu($arr, $row['id']);
echo "</li>";
$open++;
}
}
if ($open) {
echo "</ul>";
}
}
menu($array, 0);
如果您可以更改数据库表,我强烈建议您使用MPTT(修改后的预序树遍历)存储数据。它解决了很多问题**,这是一个很好的例子:http://www.sitepoint.com/hierarchical-data-database-2/
CakePHP的家伙使用MPTT和parent_id字段。
假设你不能或不想更改数据库,我会使用 PHP 对数据进行预排序,以便子项位于其父级之后的数组中,然后输出菜单。我从 uasort 的一些测试代码开始,但逻辑很快就会变得混乱。
如果您要使用 MPTT,请接受答案,如果您需要有关第二个解决方案的帮助,请添加注释。
** - 节点深度、节点路径、整个树都很容易派生,并且已经存在代码来执行此操作。