You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于多MySQL表构建Bootstrap4导航菜单的问题求助

Alright, let's tackle this problem step by step. You're trying to build a Bootstrap 4 multi-level dropdown navigation using three MySQL tables (menu, categories, products), but your buildTree function is stuck in an infinite loop and isn't outputting the correct Bootstrap structure. Let's fix this.

First, Let's Get Your Data Structured Correctly

First off, let's make sure your SQL query returns properly hierarchical data. Assuming your tables are related like menu (top-level) → categories (second-level, linked via menu_id) → products (third-level, linked via category_id), here's a query that pulls all the necessary data in order:

SELECT 
  m.id AS menu_id, m.name AS menu_name, m.url AS menu_url,
  c.id AS category_id, c.name AS category_name, c.url AS category_url,
  p.id AS product_id, p.name AS product_name, p.url AS product_url
FROM menu m
LEFT JOIN categories c ON c.menu_id = m.id
LEFT JOIN products p ON p.category_id = c.id
ORDER BY m.id, c.id, p.id;

Next, we'll convert this flat result set into a nested tree array. This avoids the infinite loop risk that comes with recursive database calls, and makes it easier to generate the HTML:

// Assume $rows is the result from your SQL query
$menuTree = [];

foreach ($rows as $row) {
    // Add top-level menu item if it doesn't exist
    if (!isset($menuTree[$row['menu_id']])) {
        $menuTree[$row['menu_id']] = [
            'id' => $row['menu_id'],
            'name' => $row['menu_name'],
            'url' => $row['menu_url'],
            'children' => []
        ];
    }

    // Add category (second-level) if it exists and isn't already added
    if (!empty($row['category_id'])) {
        $menuItem = &$menuTree[$row['menu_id']];
        if (!isset($menuItem['children'][$row['category_id']])) {
            $menuItem['children'][$row['category_id']] = [
                'id' => $row['category_id'],
                'name' => $row['category_name'],
                'url' => $row['category_url'],
                'children' => []
            ];
        }

        // Add product (third-level) if it exists
        if (!empty($row['product_id'])) {
            $categoryItem = &$menuItem['children'][$row['category_id']];
            $categoryItem['children'][] = [
                'id' => $row['product_id'],
                'name' => $row['product_name'],
                'url' => $row['product_url']
            ];
        }
        unset($menuItem, $categoryItem); // Break reference to avoid overwriting
    }
}

// Convert associative array to indexed array for easier looping
$menuTree = array_values($menuTree);

Fixing the Infinite Loop & Generating Bootstrap 4 Navigation

The infinite loop in your original buildTree function was likely caused by either:

  • Circular references in your data (e.g., a category pointing to itself as a parent)
  • Passing the entire dataset into each recursive call without proper filtering (though the above data structuring avoids this)

Now let's write recursive functions to generate the correct Bootstrap 4 HTML. Note: Bootstrap 4 doesn't natively support third-level dropdowns, so we'll add custom CSS for that.

First, the PHP Functions to Generate HTML:

// Generate top-level navbar items
function generateNavbarItems($items) {
    $html = '<ul class="navbar-nav">';
    foreach ($items as $item) {
        $hasChildren = !empty($item['children']);
        
        if ($hasChildren) {
            // Dropdown for menu items with categories
            $html .= sprintf(
                '<li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="%s" id="dropdown-%d" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        %s
                    </a>
                    <div class="dropdown-menu" aria-labelledby="dropdown-%d">
                        %s
                    </div>
                </li>',
                htmlspecialchars($item['url']),
                $item['id'],
                htmlspecialchars($item['name']),
                $item['id'],
                generateDropdownItems($item['children'])
            );
        } else {
            // Simple nav item
            $html .= sprintf(
                '<li class="nav-item">
                    <a class="nav-link" href="%s">%s</a>
                </li>',
                htmlspecialchars($item['url']),
                htmlspecialchars($item['name'])
            );
        }
    }
    $html .= '</ul>';
    return $html;
}

// Generate dropdown items (supports third-level submenus)
function generateDropdownItems($items) {
    $html = '';
    foreach ($items as $item) {
        $hasChildren = !empty($item['children']);
        
        if ($hasChildren) {
            // Third-level submenu (needs custom CSS)
            $html .= sprintf(
                '<div class="dropdown-submenu">
                    <a class="dropdown-item dropdown-toggle" href="%s">%s</a>
                    <div class="dropdown-menu">
                        %s
                    </div>
                </div>',
                htmlspecialchars($item['url']),
                htmlspecialchars($item['name']),
                generateDropdownItems($item['children'])
            );
        } else {
            // Simple dropdown item
            $html .= sprintf(
                '<a class="dropdown-item" href="%s">%s</a>',
                htmlspecialchars($item['url']),
                htmlspecialchars($item['name'])
            );
        }
    }
    return $html;
}

Then, Render the Navigation:

Add this to your HTML template:

<nav class="navbar navbar-expand-lg navbar-light bg-light">
    <a class="navbar-brand" href="/">Your Brand</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarMain" aria-controls="navbarMain" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarMain">
        <?php echo generateNavbarItems($menuTree); ?>
    </div>
</nav>

Add Custom CSS for Third-Level Dropdowns:

Bootstrap 4 doesn't include this by default, so add this to your stylesheet:

/* Support for Bootstrap 4 dropdown submenus */
.dropdown-submenu {
    position: relative;
}

.dropdown-submenu .dropdown-menu {
    top: 0;
    left: 100%;
    margin-top: -1px;
    border-top-left-radius: 0;
}

/* Responsive adjustment for mobile */
@media (max-width: 991.98px) {
    .dropdown-submenu .dropdown-menu {
        left: auto;
        top: auto;
        margin-left: 1.5rem;
    }
}

Why This Fixes the Infinite Loop

By first structuring your data into a nested array (instead of recursively querying the database or processing a flat array recursively), we eliminate the risk of infinite loops. Each level of the tree is clearly defined, and the recursive HTML generation only processes the direct children of each node, no more, no less.

Also, we added htmlspecialchars() to prevent XSS vulnerabilities—always sanitize user-generated content!

内容的提问来源于stack exchange,提问作者Alex

火山引擎 最新活动