多级菜单编程输出问题

时间:2013-09-16 17:06:45

标签: php menu multi-level

我正在尝试在php中创建一个多级菜单,但我无法正确输出html。

首先,我从db中提取数据,然后在'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>";
    }
  }
}

HTML输出

<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'的孩子,而不是父母

我知道这可能不是最好的方法,但任何人都可以告诉我我做错了什么?

2 个答案:

答案 0 :(得分:1)

1)菜单($ 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);

答案 1 :(得分:1)

如果您可以更改数据库表,我强烈建议您使用MPTT(修改后的预订树遍历)存储数据。它解决了很多问题**这是一个非常好的例子:http://www.sitepoint.com/hierarchical-data-database-2/

CakePHP人员使用MPTT和parent_id字段。

假设您不能或不想更改数据库,我会使用PHP预先排序数据,以便子节点在父节点之后位于数组中,然后输出菜单。我开始使用uasort测试代码,但逻辑很快变得混乱。

如果您要使用MPTT,请接受答案,或者如果您需要第二个解决方案的帮助,请添加评论。

** - 节点深度,节点路径,整个树很容易派生,并且代码存在已经存在。