【问题标题】:How to create "multidimensional tree menu" using PHP and SQL?如何使用 PHP 和 SQL 创建“多维树形菜单”?
【发布时间】:2014-05-25 06:28:37
【问题描述】:

我搜索了一段时间,但在 google 和其他论坛上找不到任何东西。但这很奇怪,因为它是我们大学的热门任务。所以我认为这篇文章也可能对解决同样问题的其他人有所帮助。

我有一个任务:

“创建多维树形菜单(深度未定义,可以是4或7,取决于用户的意愿),应该有添加新元素,编辑,删除和显示整个树结构等选项。使用PHP,SQL和最小CSS。”

一棵树的视觉示例:

+Menu
    +Shop
        +Tshirts
            +Yellow
            +Green
        +Pants
    +Forum
        +Ideas

如您所见,它有 4 个深度级别:Menu->Shop->tshirt->yellow 但我必须做到这一点,以便用户可以添加任意数量的关卡和元素。

是否有任何示例以及我应该继续使用哪种 SQL 结构? 谢谢!

【问题讨论】:

标签: php html css sql


【解决方案1】:

我建议 MySQL 采用以下结构:

I_ID (unique, auto-increment), Item Name, Item Parent ID, Children

“儿童”可能包含该特定项目的每个“儿童”的 I_ID 的 base64 编码、序列化 PHP 数组。

根元素将有一个“父 ID”为“root”或“-1”之类的东西,因此要从数据库中检索它,您首先需要 SELECT 任何具有 parent 的根或-1 或任何你选择的。这是任意的。

然后,使用 PHP,您将解码 children 数组,并从系统中选择每个 ID。

重复直到没有更多的孩子。递归函数在这里可以很好地为您服务。

当你将每一行添加到 DOM 中时,给它们一个特定的类,使它们隐藏起来。单击“+”时,使用 javascript 将该元素的所有子元素更改为具有未隐藏的类,并将刚刚单击的“+”按钮替换为“-”按钮。类似地处理减号按钮。

【讨论】:

    【解决方案2】:

    解决方法很简单:

    SQL 结构 table menu_entries (int id, varchar title, varchar link, int level, bool is_parent)

    您可以添加附加链接、颜色等选项。

    默认级别为 1。 默认 is_parent = false;

    然后继续将您的条目输入数据库。如果 item 有 subitems - is_parent = true,并且所有 subitem 的 level +1 parent 的 level。

    在输出中只需添加任何新“级别”项目缩进的格式。 此外,如果项目的链接是页面的当前 URL - 将项目突出显示为活动的。

    就是这样。

    【讨论】:

      【解决方案3】:

      您希望使用 ID 和 parentID 保存数据库中的每个元素(如果不存在这样的父 ID,则可以为 null)。 PHP 是您“最大”的问题,但参考是您将平面结构转变为树形结构的好朋友。

      考虑以下数据库结果:

      ----------------------------
      | id | parentID | text     |
      |----|----------|----------|
      | 1  | null     | Item #1  |
      | 2  | 5        | Item #2  |
      | 3  | 2        | Item #3  |
      | 4  | 2        | Item #4  |
      | 5  | null     | Item #5  |
      | 6  | 5        | Item #6  |
      | 7  | 3        | Item #7  |
      | 8  | 5        | Item #8  |
      | 9  | 1        | Item #9  |
      | 10 | 7        | Item #10 |
      ----------------------------
      

      考虑以下数组(可能来自数据库结果 - 但是,ID 是键很重要。您可以简单地将数据库结果转换为以下内容(唯一需要的键是“parentID”):

      $menu = array(
          1 => array('text' => 'Item #1', 'parentID' => null),
          2 => array('text' => 'Item #2', 'parentID' => 5),
          3 => array('text' => 'Item #3', 'parentID' => 2),
          4 => array('text' => 'Item #4', 'parentID' => 2),
          5 => array('text' => 'Item #5', 'parentID' => null),
          6 => array('text' => 'Item #6', 'parentID' => 5),
          7 => array('text' => 'Item #7', 'parentID' => 3),
          8 => array('text' => 'Item #8', 'parentID' => 5),
          9 => array('text' => 'Item #9', 'parentID' => 1),
         10 => array('text' => 'Item #10', 'parentID' => 7),
      );
      

      并将其变成树形结构:

      <?php    
      $addedAsChildren = array();
      
      foreach ($menu as $id => &$menuItem) { // note that we use a reference so we don't duplicate the array
          if (!empty($menuItem['parentID'])) {
              $addedAsChildren[] = $id; // it should be removed from root, but we'll do that later
      
              if (!isset($menu[$menuItem['parentID']]['children'])) {
                  $menu[$menuItem['parentID']]['children'] = array($id => &$menuItem); // & means we use the REFERENCE
              } else {
                  $menu[$menuItem['parentID']]['children'][$id] = &$menuItem; // & means we use the REFERENCE
              }
          }
      
          unset($menuItem['parentID']); // we don't need parentID any more
      }
      
      unset($menuItem); // unset the reference
      
      foreach ($addedAsChildren as $itemID) {
          unset($menu[$itemID]); // remove it from root so it's only in the ['children'] subarray
      }
      

      有了这个新数组,我们可以使用一个简单的递归函数以ul..li 的方式输出它:

      echo makeTree($menu);
      
      function makeTree($menu) {
          $tree = '<ul>';
      
          foreach ($menu as $id => $menuItem) {
              $tree .= '<li>' . $menuItem['text'];
      
              if (!empty($menuItem['children'])) {
                  $tree .= makeTree($menuItem['children']);
              }
      
              $tree .= '</li>';
          }
      
          return $tree . '</ul>';
      }
      

      导致:

      <ul><li>Item #1<ul><li>Item #9</li></ul></li><li>Item #5<ul><li>Item #2<ul><li>Item #3<ul><li>Item #7<ul><li>Item #10</li></ul></li></ul></li><li>Item #4</li></ul></li><li>Item #6</li><li>Item #8</li></ul></li></ul>
      

      ..并渲染:

      DEMO

      【讨论】:

      • 那么我的数据库中需要多少个表呢?它如何知道哪个是父母,哪个是孩子?你能在代码中放一些 cmets 吗?我在这里有点困惑。谢谢!
      • @Ignas 只有一个表,每个菜单项有一行。 “id”是项目的 ID,“parentID”是父菜单项的 ID。
      • IKt 正在工作,但它如何知道谁是谁的孩子?你能解释一下这行吗:$meniu[$meniuItem['parentID']]['children'] - 你从哪里得到的['children']
      • @Ignas $menu[$menuItem['parentID']] 将是父 $menuItem(如果 parentID 为 5,则等于 $menu[5])。在这里,我们首先检查“它是否有children 键?”如果没有,我们将创建它,但如果它已经有一个 children 键,那么我们只需将项目添加到该数组。
      • 哦,我明白了,后来我们决定谁是父母后,我们取消设置对吗?
      【解决方案4】:

      这是我的链接目录脚本的类别表中的代码,可以满足您的需求:

      数据库设计:

      CREATE TABLE IF NOT EXISTS `categories` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `name` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
        `parent` int(11) DEFAULT NULL,
        PRIMARY KEY (`id`)
      )
      

      使用 PHP 以破折号将它们打印出来:

      function parse($tree,$parent = 0,$level = 0){
          $level++;
          foreach ($tree as $p)  {
              if ($p['parent'] != $parent) continue;
              $p['name'] = str_repeat('-',$level-1) . $p['name'];
              echo "<option name='cat' value='{$p['id']}'>{$p['name']}</option>";
              parse ($tree, $p['id'],$level);
          }
      }
      
          $q = $link->query("SELECT * FROM `categories` ORDER BY name ASC");
          $cats = array();
          while($row = $q->fetch()){
              $cats[] = array("id"=>$row['id'],"name"=>$row['name'],"parent"=>$row['parent'],"level"=>0);
          }
      
      parse($cats)
      

      如果你使用,你可以删除 $level 参数

    • 而不是输出的破折号数。
    • 【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-06
        相关资源
        最近更新 更多