【问题标题】:Build dynamic Mega Menu using recursion?使用递归构建动态超级菜单?
【发布时间】:2013-03-21 12:54:15
【问题描述】:

我正在尝试使用 PHP 创建一个超级菜单,但在正确输出结构时遇到了问题。我已经对 Mega Menu 进行了硬编码来测试所有内容,它工作正常,但显然我需要 PHP 来为我创建它。

我有一个超级菜单硬编码的示例,因此每个人都可以看到我正在尝试创建的内容:

http://www.libertyeaglearms.com/dev

或者这里是代码:

期望的输出:

    <div id="wrapper">
        <ul class="mega-menu">
            <li class="mega-menu-drop">
                <a href="#">Firearms</a>
                 <div class="mega-menu-content">
                     <div class="column">
                         <h4>Rifles</h4>
                          <ul>
                              <li><a href="#">One</a></li>
                              <li><a href="#">Two</a></li>
                              <li><a href="#">Three</a></li>
                              <li><a href="#">Four</a></li>
                              <li><a href="#">Five</a></li>
                          </ul>
                      </div>
                      <div class="column">
                          <h4>Handguns</h4>
                          <ul>
                              <li><a href="#">One</a></li>
                              <li><a href="#">Two</a></li>
                              <li><a href="#">Three</a></li>
                              <li><a href="#">Four</a></li>
                              <li><a href="#">Five</a></li>
                          </ul>
                      </div>
                      <div class="column">
                          <h4>Shotguns</h4>
                          <ul>
                              <li><a href="#">One</a></li>
                              <li><a href="#">Two</a></li>
                              <li><a href="#">Three</a></li>
                              <li><a href="#">Four</a></li>
                              <li><a href="#">Five</a></li>
                          </ul>
                      </div>
                  </div>
              </li>
              <li class="mega-menu-drop">
                  <a href="#">Archery</a>
                  <div class="mega-menu-content">
                      <div class="column">
                          <h4>Bows</h4>
                          <ul>
                              <li><a href="#">One</a></li>
                              <li><a href="#">Two</a></li>
                              <li><a href="#">Three</a></li>
                              <li><a href="#">Four</a></li>
                              <li><a href="#">Five</a></li>
                          </ul>
                      </div> 
                      <div class="column">
                          <h4>Arrows</h4>
                          <ul>
                              <li><a href="#">One</a></li>
                              <li><a href="#">Two</a></li>
                              <li><a href="#">Three</a></li>
                              <li><a href="#">Four</a></li>
                              <li><a href="#">Five</a></li>
                          </ul>
                      </div>
                  </div>
              </li> 
          </ul>
      </div>

当前输出:(非常混乱。请注意,哈哈)

<div id="wrapper">
    <ul class="mega-menu">
    <li class="mega-menu-drop">
            <a href="#">archery</a>
            <div class="mega-menu-content">
                <div class="column">
                    <h4>compound</h4>
            <ul>
            <h4>bows</h4>
            <ul>
            </div>
        </li>
        <li class="mega-menu-drop">
            <a href="#">firearms</a>
            <div class="mega-menu-content">
                <div class="column">
                    <h4>rifle ammunition</h4>
                    <ul>
            <h4>ammunition</h4>
                    <ul>
            </div>
        </li>
            </ul>  
        </div>

这里是我的 PHP:

$json = json_decode($category->buildDepartments(NULL),true);
function buildDepartments($array,$parent)
{
    $html = '';                 
    foreach($array as $category)
    {
        if($category['parent'] == $parent)
        {
             if($category['parent'] == NULL)
             {
                 $html .= '<li class="mega-menu-drop">' . "\n\t\t\t\t";
                 $html .= '<a href="#">'.$category['category_name'].'</a>' . "\n\t\t\t\t";
                 $html .= '<div class="mega-menu-content">' . "\n\t\t\t\t\t";                            
                 $html .= '<div class="column">' . "\n\t\t\t\t\t\t";
                 $html .= buildDepartments($array,$category['category_id']);                            
                 $html .= '</div>' . "\n\t\t\t";
                 $html .= '</li>' . "\n\t\t\t";
              }
              else
              {
                  $html .= buildDepartments($array,$category['category_id']);
                  $html .= '<h4>'.$category['category_name'].'</h4>' . "\n\t\t\t\t\t\t";
                  $html .= '<ul>' . "\n\t\t\t\t";

               }                        
          }
    }
    return $html;
}
print(buildDepartments($json,NULL));

这是我的数据库:

赏金后编辑

根据 icktoofay 的建议,我似乎无法弄清楚 foreach() 循环。我遇到的问题是当我应该看到类别和子类别时,我在大型菜单中获得了部门名称。我认为问题是我需要使用特定的父 ID 执行循环才能获取所有孩子,但我不确定这是否是问题所在。代码如下:

<div id="wrapper">
<ul class="mega-menu">         
    <?php $json = json_decode($category->buildDepartments(NULL)); ?>
    <?php foreach($json as $category): ?>
        <li class="mega-menu-drop">
            <a href="#"><?php if($category->parent === NULL){echo $category->category_name;} ?></a>
            <div class="mega-menu-content">                 
                <?php foreach($category as $subcategory): ?>
                <div class="column">
                    <?php if($category->category_id === $category->parent){echo '<h4>' . $category->category_name . '</h4>';}?>
                    <ul>
                        <?php foreach($category as $subcategory)
                        {
                            echo '<li>' . $category->category_name . '</li>';
                        }
                        ?>
                    </ul>
                </div>
                <?php endforeach; ?>                   
            </div>
        </li>
     <?php endforeach; ?>  
</ul>  
</div>

【问题讨论】:

  • 我在某处有这样的脚本,但都是阿尔巴尼亚语 cmets IIRC。
  • 如果您不介意分享,我不介意阿尔巴尼亚 cmets。
  • 那些实际上是在开玩笑说您的问题有军事类比,但是,我们有关于您的类别的父子关系的现有问答材料。作为入门问题,我建议将以下问题作为该主题的参考问题:How can I convert a series of parent-child relationships into a hierarchical tree?。注意那个问答中的相关链接,它们包括查询表单 Mysql 以及非常详细地提交 HTML。而且都是简单的英语;)
  • 很棒的链接!谢谢你的信息,很有帮助。我花了一段时间,但我得到了阿尔巴尼亚人的参考资料 ;-) 太棒了!现在我要上“老大哥”监视名单了,哈哈。

标签: php recursion


【解决方案1】:

由于它是固定的深度,并且每个级别的格式不同,因此递归可能不合适。此外,将所有内容都放在字符串中是不雅的。相反,您可能想尝试像这样将 HTML 和循环编织在一起:

<div id="wrapper">
    <ul class="mega-menu">
        <?php foreach($categories as $category): ?>
            <li class="mega-menu-drop">
                <a href="#"><?php echo $category->name; ?></a>
                <div class="mega-menu-content">
                    <?php foreach($category->subcategories as $subcategory): ?>
                        <!-- and so on -->
                    <?php endforeach; ?>
                </div>
            </li>
        <?php endforeach; ?>
    </ul>
</div>

我在这里使用的代码假设您已经将它从一个平面数组排序到一个树状结构。例如,如果我们有一个 Category 类:

class Category {
    public $id;
    public $parentID;
    public $name;
    public $parent;
    public $subcategories;

    public function __construct($id, $parentID, $name) {
        $this->id = $id;
        $this->parentID = $parentID;
        $this->name = $name;
        $this->parent = null;  // will be filled in later
        $this->subcategories = array();  // will be filled in later
    }
}

像您可能从数据库调用(我们将其称为$flatCategories)中获得的关联数组数组,我们可以构建一堆尚未连接的Category 实例,如下所示:

$categories = array();
foreach($flatCategories as $flatCategory) {
    $categories[$flatCategory['id']] =
        new Category($flatCategory['category_id'],
                     $flatCategory['parent'],
                     $flatCategory['category_name']);
}

然后我们可以将它们全部连接成一个层次结构:

foreach($categories as $category) {
    if($category->parentID !== null) {
        $category->parent = $categories[$category->parentID];
        $category->parent->subcategories[] = $category;
    }
}

现在它们都连接起来了,我们只关心保留对根的引用:

$roots = array();
// This could, of course, be merged into the last loop,
// but I didn't for clarity.
foreach($categories as $category) {
    if($category->parentID === null) {
        $roots[] = $category;
    }
}

现在$roots 包含所有根类别,并且遍历起来相当简单。在顶部的示例中,我假设 $categories 中包含类似于 $roots 的内容。

【讨论】:

  • 最初我有两个函数,但我也无法让它工作。我认为递归是我最好的选择,但我会弄乱你得到的东西,看看我能把什么放在一起。谢谢你:)
  • 我尝试了您的建议,但我正忙于 for 循环。我认为我需要以一种可以长时间传递parent id 的方式来构建它。你能看一下,让我知道你的想法吗?我在描述中添加了我的代码。
  • @Mike:当我第一次编写代码时,我假设您会发现我要求它采用层次结构而不是直接从数据库中取出的平面数组。事后看来,这并不是那么明显。我添加了一些代码,展示了如何将数据库输出转换为我在代码中使用的更可行的结构。
  • 非常感谢您的耐心和时间。有时某些事情,甚至是基本任务,都需要我一段时间才能消化。再一次,像您这样的人使这个网站成为一个宝贵的教育工具。我已经在脑海中想出了我需要做什么,所以我会实施这个并回来:-)
【解决方案2】:

您需要生成称为超级树的东西并使用递归函数来回显每个分支,这将允许无限深度树,但它也允许未知深度树。

首先,SQL:

SELECT category_id, parent, category_name

二、使用SQL创建树:

$super_tree = array();
while(($row = mysql_fetch_assoc($res)) != NULL) {
  $parent = $row['parent'] == NULL ? 0 : $row['parent']; //clean up the parent

  $super_tree[$parent][$row['category_id']] = $row['category_name'];
}

第三,回显树

function echo_branch($tree_branch, $tree_root) {
  echo("<ul>\n"); //open up our list for this branch

  foreach($tree_branch as $id => $name) { //foreach leaf on the branch
    echo("<li>"); //create a list item

    echo("<a href=\"#{$id}\">{$name}</a>"); //echo out our link

    if(!empty($tree_root[$id])) { //if our branch has any sub branches, echo those now
      echo_branch($tree_root[$id], $tree_root); //pass the new branch, plus the root
    }

    echo("</li>\n"); //close off this item
  }
  echo("</ul>\n"); //close off this list
}

echo_branch($super_tree[0], $super_tree); //echo out unlimited depth tree structure

这允许您的树结构的无限深度,并允许简单的代码能够在代码库中创建结构。

您现在需要做的就是在正确的位置添加额外的内容,例如类和额外的 html 元素。

如果您希望跟踪树的当前深度以便能够根据深度回显不同的内容,您可以进行以下更改

在函数定义中

function echo_branch($tree_branch, $tree_root, $depth) {

在 if 内的递归调用中

echo_branch($tree_root[$id], $tree_root, $depth++);

在初次通话中

echo_branch($super_tree[0], $super_tree, 0);

【讨论】:

    【解决方案3】:

    看起来你正在使用变量

    $category 
    

    什么时候应该使用

    $subcategory
    

    试试这个:

    <div id="wrapper">
    <ul class="mega-menu">         
        <?php $json = json_decode($category->buildDepartments(NULL)); ?>
        <?php foreach($json as $category): ?>
            <li class="mega-menu-drop">
                <a href="#"><?php if($category->parent === NULL){echo $category->category_name;} ?></a>
                <div class="mega-menu-content">                 
                    <?php foreach($category as $subcategory): ?>
                    <div class="column">
                        <?php if($subcategory->category_id === $category->parent){echo '<h4>' . $category->category_name . '</h4>';}?>
                        <ul>
                            <?php foreach($subcategory as $subcategory2)
                            {
                                echo '<li>' . $subcategory2->category_name . '</li>';
                            }
                            ?>
                        </ul>
                    </div>
                    <?php endforeach; ?>                   
                </div>
            </li>
         <?php endforeach; ?>  
    </ul>  
    </div>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多