2
 <?php
// Select all entries from the menu table
$sql1 = $pardConfig->prepare("SELECT id, menu_title, menu_link, parent FROM pard_menu ORDER BY parent, sort, menu_title");
// Create a multidimensional array to conatin a list of items and parents
$sql1->execute();

$menu = array(
    'items' => array(),
    'parents' => array()
);
// Builds the array lists with data from the menu table
while ($items = $sql1->fetch()) {
    // Creates entry into items array with current menu item id ie. $menu['items'][1]
    $menu['items'][$items['id']]         = $items;
    // Creates entry into parents array. Parents array contains a list of all items with children
    $menu['parents'][$items['parent']][] = $items['id'];
}


// Menu builder function, parentId 0 is the root
function buildMenu($pardConfig, $parent, $menu)
{
    $html = "";
    if (isset($menu['parents'][$parent])) {
        $html .= "
<ul>\n";
        foreach ($menu['parents'][$parent] as $itemId) {
            if (!isset($menu['parents'][$itemId])) {
                $html .= "<li>\n <a href='" . $menu['items'][$itemId]['menu_link'] . "'>" . $menu['items'][$itemId]['menu_title'] . "</a>\n</li> \n";
            }
            if (isset($menu['parents'][$itemId])) {
                $html .= "
<li>\n <a href='" . $menu['items'][$itemId]['menu_link'] . "'>" . $menu['items'][$itemId]['menu_title'] . "</a> \n";
                $html .= buildMenu($pardConfig, $itemId, $menu);
                $html .= "</li> \n";
            }
        }
        $html .= "</ul> \n";
    }
    return $html;
}
echo buildMenu($pardConfig, 0, $menu);

?>

上面的代码包含一个用于创建具有多级子菜单的动态菜单的 php 代码。我为此预定义了类...

  1. 对于主要ul(第一 Ul)我有.nav
  2. 对于任何li有一级子菜单的地方,我都有.dropdownli 类
  3. 另外对于第二步,我有一个元素.dropdown-menuul,它有一个父元素作为li
  4. 我有一个.dropdown-submenu3 级子菜单的课程

所以我想修改我的代码,将这 4 个 setps 添加到其中?任何帮助,将不胜感激 ?

我将为此使用引导程序菜单 API

看看@这个

我用 Jquery 完成了这种方法,如下所示。但它不是 100% 好..

   $(".nav-collapse").find("ul").first().addClass("nav");
   $(".nav-collapse").find("li").has("ul").addClass("nav");
   $(".nav").find("li:has(ul) a").attr("data-toggle", "dropdown");
   $('ul').filter(function () {
       return $(this).parent().is('li')
   }).addClass('dropdown-menu');
   $(".nav").find("li ul li").addClass("dropdown-submenu");
   $('.dropdown-toggle').dropdown();
   });
4

1 回答 1

4

通过不使用对象来表示菜单元素,您自己的代码变得困难。正因为如此,并且因为您在渲染它的同时有效地构建了菜单结构,所以您的代码很难阅读,也很难思考,这就是为什么您发现很难做到你想要什么。

重构代码以使用菜单元素的类将菜单的构建与呈现它完全分开,并且更容易放置明确的函数来决定如何呈现它。

class MenuElement {

    var $parent = null;
    var $children = array();

    var $menuTitle;
    var $menuLink;

    function __construct($parent, $menuTitle, $menuLink){
        $this->parent = $parent;
        $this->menuTitle = $menuTitle;
        $this->menuLink = $menuLink;
    }

    function hasParent(){
        if ($this->parent) {
            return true;
        }
        return false;
    }

    function addChild($child){
        $this->children[] = $child;
    }

    function hasChildren(){
        return count($children);
    }    

    function hasGrandParent(){
        if ($this->parent) {
            return $this->parent->hasParent();
        }
        return false;
    }

    function render() {
        $navClass = '';
        $ulClass = '';
        $liClass = '';

        if ($this->parent == false) {
            //For main ul (First Ul) i have .nav class
            $navClass = 'nav';
        }

        if (count($this->children)){
            //For any li where has first level sub menus i have .dropdown class for li
            $liClass = 'dropdown';
        }


        if($this->parent) {
            //Additionally for 2nd step i have .dropdown-menu class for 
            //ul elemnts which it has a parent element as a li
            $ulClass = 'dropdown-menu';
        }
        if ($this->hasGrandParent() == true){
            //And i have a .dropdown-submenu class for 3rd level sub menus
            $ulClass = 'dropdown-submenu';
            //$ulClass .= ' dropdown-submenu'; if you wanted both classes
        }

        $output = "<ul class='$navClass'>";
        $output .= "<li class='$liClass'>";
        $output .= "<a href='".$this->menuLink."'>".$this->menuTitle."</a>";

        foreach ($this->children as $child) {
            $output .= $child->render();
        }

        $output .= "</li>";
        $output .= '</ul>';

        return $output;
    }
}


//Builds a menu and returns the root element of it.
function buildMenu(){
    $rootElement = null;
    // Select all entries from the menu table
    $sql1 = $pardConfig->prepare("SELECT id, menu_title, menu_link, parent FROM pard_menu ORDER BY parent, sort, menu_title");
    // Create a multidimensional array to conatin a list of items and parents
    $sql1->execute();

    $menuElements = array();

    while ($items = $sql1->fetch()) {
        $parent = null;

        $parentID = $items['parent'];

        if ($parentID) {
            if(array_key_exists($parentID, $menuElements) == true) {
                $parent = $menuElements[$parentID];
            }
            else{
                throw \Exception("Tried to reference parent which doesn't exist");
            }
        }

        $id = $items['id'];
        $menuElements[$id] = new MenuElement($parent, $items['menu_title'], $items['menu_link']);

        if ($id == 0) {
            $rootElement = $menuElements[$id];
        }

        if ($parent) {
            $parent->addChild($menuElements[$id]);
        }
    }

    if ($rootElement == null) {
        throw Exception("Root element not found, menu is borked");
    }

    //TODO - you may prefer to return $menuElements
    return $rootElement;
}


$menu = buildMenu();
$output = $rootElement->render();
echo $output;

顺便说一句,这在一个地方仍然是糟糕的代码,因为它将从数据库中检索菜单与构建它混合在一起。最好也将它们分开,以便您可以从您希望的任何数据源动态构建菜单。

此外,表中的列名parent会更好,parentID因为这样可以防止 $parentID 变量(它是一个 ID)和 $parent 变量(它是一个对象)之间的混淆。

不,我没有调试过这个 - 答案只是为了展示它是如何完成的。

于 2013-06-21T15:17:36.093 回答