【问题标题】:multi level menu programming output issue多级菜单编程输出问题
【发布时间】:2013-09-16 17:06:44
【问题描述】:

我正在尝试在 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' 的子级而不是父级

我知道这可能不是最好的方法,但谁能告诉我我做错了什么?

【问题讨论】:

    标签: php menu multi-level


    【解决方案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);
    

    【讨论】:

    • 哦,天哪.. 太容易了.. 我不敢相信我浪费了 2 天时间来思考如何去做,而且如此简单,更有意义.. 非常感谢
    • btw.. 是 echo ($open?'':'
        ')
      而不是 echo ($open?'
        ':' ')
    • 意思是if ($open) {/* echo nothing */} else { echo '&lt;ul&gt;'; }
    • 我修好了,请重新检查
    【解决方案2】:

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

    CakePHP 家伙使用 MPTT 和 parent_id 字段。

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

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

    ** - 节点深度、到节点的路径、整棵树都很容易推导出来,并且已经有代码可以做到这一点。

    【讨论】:

    • +1 非常感谢。我会研究它,因为对我来说是新东西。但现在@Alexandr 的答案是我需要的
    • 我同意。需要注意的一件事是他的解决方案是 O(n^2) 解决方案。对于具有少量用户或数据集的应用程序来说,这不是一个大问题。如果我要使用递归,我会使用它通过合并排序重新排序数据,这是一个 O(log(n)) 解决方案(或者更好的是使用 uasort,它允许您只关注比较器)。令人惊讶的是,我看到“企业”级软件中包含此类 O(n^2) 解决方案的次数令人惊讶(在我的上一份合同中,消除其中一个将 Web 服务调用速度提高了 10,000%)。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    相关资源
    最近更新 更多