Меню навигации PHP Bootstrap 4 с подменю

ОРИГИНАЛЬНЫЙ ПОЧТ

Я хочу создать меню навигации в PHP с помощью Bootstrap 4. Проблема в том, что один из <li> не подходит (тот, что из dropdown, он не раскрывается, а просто обычный nav-item). Этот код работает нормально, если вы хотите создать нормальное меню с <ul> и <li>, но для начальной загрузки вам необходимо иметь nav-item dropdown на <li> с идентификатором 2 с именем Dropdown. Как бы я это сделал?

Надеюсь, этой информации достаточно.

Это array ():

array (size=3)
  0 => 
    array (size=5)
      0 => 
        array (size=3)
          'id' => string '1' (length=1)
          'menu_naam' => string 'Home' (length=4)
          'parent_id' => string '0' (length=1)
      1 => 
        array (size=3)
          'id' => string '2' (length=1)
          'menu_naam' => string 'Dropdown' (length=4)
          'parent_id' => string '0' (length=1)
      2 => 
        array (size=3)
          'id' => string '3' (length=1)
          'menu_naam' => string 'Winkelwagen' (length=11)
          'parent_id' => string '0' (length=1)
      3 => 
        array (size=3)
          'id' => string '4' (length=1)
          'menu_naam' => string 'Contact' (length=7)
          'parent_id' => string '0' (length=1)
      4 => 
        array (size=3)
          'id' => string '5' (length=1)
          'menu_naam' => string 'Feedback' (length=8)
          'parent_id' => string '0' (length=1)
  2 => 
    array (size=1)
      0 => 
        array (size=3)
          'id' => string '6' (length=1)
          'menu_naam' => string 'Sub Menu' (length=8)
          'parent_id' => string '2' (length=1)
  6 => 
    array (size=1)
      0 => 
        array (size=3)
          'id' => string '7' (length=1)
          'menu_naam' => string 'Sub Sub Menu' (length=12)
          'parent_id' => string '6' (length=1)

Это PHP, который я использую для создания меню:

<?php
function menu_builder() {
global $pdo;

   $sql = $pdo->prepare("SELECT * FROM menus");

   if ($sql->execute()) {
        while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
             $array[$row['parent_id']][] = $row;
        }
        loop_array($array);
    }
}
function loop_array($array = array(), $parent_id = 0) {
    if (!empty($array[$parent_id])) {
        echo "<ul class=\"navbar-nav mr-auto\">";
        foreach ($array[$parent_id] as $item) {
            echo "<li class=\"nav-item\">";
            echo "<a href=\"#\" class=\"nav-link\">" . $item['menu_naam'] . "</a>";
            loop_array2($array, $item['id']);
            echo "</li>";
        }
        echo "</ul>";
    }
}
function loop_array2($array = array(), $parent_id = 0) {
    if (!empty($array[$parent_id])) {
        echo "<li class=\"nav-item dropdown\">";
        foreach ($array[$parent_id] as $item) {
            echo "<a href=\"#\" class=\"nav-link dropdown-toggle\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">" . $item['menu_naam'] . "</a>";
            loop_array3($array, $item['id']);
        }
        echo "</li>";
    }
}
function loop_array3($array = array(), $parent_id = 0) {
    if (!empty($array[$parent_id])) {
        echo "<div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">";
        foreach ($array[$parent_id] as $item) {
            echo "<a class=\"dropdown-item\" href=\"#\">" . $item['menu_naam'] . "</a>";
        }
        echo "</div>";
    }
}

Я действительно надеюсь, что кто-то может мне помочь с этим, следует ли мне добавить что-то в базу данных, чтобы он знал, что это раскрывающийся список? Я думаю, что мой код слишком большой и сложный, должен быть более простой способ, но я не знаю, как это сделать. Думаю, мне нужен совершенно другой подход. Если бы ты только мог помочь мне в правильном направлении, это тоже было бы хорошо.

Также небольшая благодарность парню, который сделал учебник по подменю (здесь вы также можете увидеть, как меню построено с помощью <ul> и <li> и делает именно то, что ему нужно, но не для bootstrap): https://thewikihow.com/video_Ol63V4R-TdI

Обновлено: Я нашел здесь своего рода решение: Динамическое меню php bootstrap mysql

Что у меня сейчас есть:

function drawMenu($pdo, $parent_id, $level = null) {
    $sql = $pdo->prepare("SELECT * FROM menus where parent_id = $parent_id");
    $sql->execute();

    foreach ($sql->fetchAll() as $row) {
        $sql = $pdo->prepare("SELECT count(*) FROM menus where parent_id = " . $row['id'] . "");
        $sql->execute();
        // The item is parent, so do recursion again
        //var_dump($sql->fetchAll()[0][0]);
        if ($sql->fetchAll()[0][0] !== '0' && $level !== 0){ 
            echo "<li class=\"nav-item dropdown\"><a href=\"" . $row['url'] . "\" class=\"nav-link dropdown-toggle\" id=\"navbarDropdownMenuLink\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">" . $row['menu_naam'] . "</a><div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdownMenuLink\">\n";
            drawMenu($pdo, $row[0], $level - 1);
            echo "</div></li>\n";
        }
        else { // The item is a leaf or we reach the end level, i.e. base case, so do print the item label 
            echo "<li class=\"nav-item\"><a href=\"#\" class=\"nav-link\">" . $row['menu_naam'] . "</a></li>\n";
        }
    }
}
?>
<header class = "navbar navbar-dark bg-dark fixed-top navbar-expand-sm">
    <a class = "navbar-brand" href = "#">Webshop</a>
    <button class = "navbar-toggler" style = "background: #000000" type = "button" data-toggle = "collapse" data-target = "#navbar-header" aria-controls = "navbar-header">
        &#9776;
    </button>
    <div class = "navbar-collapse collapse show" id = "navbar-header">
        <ul class = "navbar-nav mr-auto">
        <?php
        drawMenu($pdo, 0, null);
        ?>
        </ul>
    </div>
</header>

Но проблема в том, что он печатает несколько

<div class = "dropdown-menu" aria-labelledby = "navbarDropdownMenuLink">

HTML теперь выглядит так:

<div class = "navbar-collapse collapse show" id = "navbar-header">
    <ul class = "navbar-nav mr-auto">
        <li class = "nav-item"><a href = "#" class = "nav-link"><span class = "fas fa-home"></span> Home</a></li>
        <li class = "nav-item dropdown"><a href = "#" class = "nav-link dropdown-toggle" id = "navbarDropdownMenuLink" data-toggle = "dropdown" aria-haspopup = "true" aria-expanded = "false">Dropdown</a><div class = "dropdown-menu" aria-labelledby = "navbarDropdownMenuLink">
        <li class = "nav-item dropdown"><a href = "#" class = "nav-link dropdown-toggle" id = "navbarDropdownMenuLink" data-toggle = "dropdown" aria-haspopup = "true" aria-expanded = "false">Sub Menu</a><div class = "dropdown-menu" aria-labelledby = "navbarDropdownMenuLink">
        <li class = "nav-item"><a href = "#" class = "nav-link">Sub-sub Menu</a></li>
        </div></li>
        </div></li>
        <li class = "nav-item"><a href = "#" class = "nav-link"><span class = "fas fa-shopping-cart"> </span> Winkelwagen</a></li>
        <li class = "nav-item"><a href = "#" class = "nav-link">Contact</a></li>
        <li class = "nav-item"><a href = "#" class = "nav-link">Feedback</a></li>
    </ul>
</div>
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
0
3 373
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я добавил menu в базу данных и проверил, 0 или 1. Я удалил подменю, но обновлю этот пост, если добавлю их.

function menu_builder($pdo, $parent_id) {
    $sql = $pdo->prepare("SELECT * FROM menus");
    if ($sql->execute()) {
        while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
             $array[$row['parent_id']][] = $row;
        }
        main_menu($array);
    }
}
function main_menu ($array, $parent_id = 0) {
    if (!empty($array[$parent_id])) {
        foreach ($array[$parent_id] as $item) {
            if ($item['menu'] == '0') {
                echo "  <li class=\"nav-item\">" . PHP_EOL;
                echo "    <a class=\"nav-link\" href=\"#\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
                main_menu($array, $item['id']);
                echo "  </li>" . PHP_EOL;
            }
            elseif ($item['menu'] == '1') {
                echo "  <li class=\"nav-item dropdown\"><a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
                sub_menu($array, $item['id']);
                echo "  </li>" . PHP_EOL;
            }
        }
        //echo "</div>" . PHP_EOL;
        echo "</li>" . PHP_EOL;
    }
}
function sub_menu ($array, $parent_id) {
    if (!empty($array[$parent_id])) {
        echo "    <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">" . PHP_EOL;
        foreach ($array[$parent_id] as $item) {
            echo "      <a class=\"dropdown-item\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
        }
        echo "    </div>" . PHP_EOL;
    }
}

?>
<header class = "navbar navbar-dark bg-dark fixed-top navbar-expand-sm">
    <a class = "navbar-brand" href = "#">Webshop</a>
    <button class = "navbar-toggler" style = "background: #000000" type = "button" data-toggle = "collapse" data-target = "#navbar-header" aria-controls = "navbar-header">
        &#9776;
    </button>
    <div class = "navbar-collapse collapse show" id = "navbar-header">

        <?php
        echo "<ul class=\"navbar-nav mr-auto\">";
        echo menu_builder($pdo, 0);
        echo "</ul>" . PHP_EOL;    
        ?>
    </div>
</header>

РЕДАКТИРОВАТЬ: чтобы иметь подменю, код выглядит так, и вам также понадобится следующий css.

function menu_builder($pdo, $parent_id) {
    $sql = $pdo->prepare("SELECT * FROM menus");
    if ($sql->execute()) {
        while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
             $array[$row['parent_id']][] = $row;
        }
        main_menu($array);
    }
}
function main_menu ($array, $parent_id = 0) {
    if (!empty($array[$parent_id])) {
        foreach ($array[$parent_id] as $item) {
            if ($item['menu'] == '0') {
                echo "            <li class=\"nav-item\">" . PHP_EOL;
                echo "                <a class=\"nav-link\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
                main_menu($array, $item['id']);
                echo "            </li>" . PHP_EOL;
            }
            elseif ($item['menu'] == '1') {
                echo "            <li class=\"nav-item dropdown\">". PHP_EOL;
                echo "                <a class=\"nav-link dropdown-toggle\" href=\"" . $item['url'] . "\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
                sub_menu($array, $item['id']);
                echo "            </li>" . PHP_EOL;
            }
        }
    }
}
function sub_menu ($array, $parent_id) {
    if (!empty($array[$parent_id])) {
        echo "                <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">" . PHP_EOL;
        foreach ($array[$parent_id] as $item) {
            if ($item['sub_menu'] == '0') { 
                echo "                    <a class=\"dropdown-item\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
            }
            elseif ($item['sub_menu'] == '1') {
                echo "                    <div class=\"dropdown-submenu\">" . PHP_EOL;
                echo "                        <a class=\"dropdown-item dropdown-toggle\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
                sub_sub_menu($array, $item['id']);
                echo "                    </div>" . PHP_EOL;
            }
        }
        echo "                </div>" . PHP_EOL;
    }
}
function sub_sub_menu ($array, $parent_id) {
    if (!empty($array[$parent_id])) {
        echo "                    <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">" . PHP_EOL;
        foreach ($array[$parent_id] as $item) {
            echo "                        <a class=\"dropdown-item\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
        }
    }
    echo "                    </div>" . PHP_EOL;
}

CSS, который вам нужен для подменю, потому что бутстрап не поддерживает его по умолчанию (https://stackoverflow.com/a/45755948/2877035):

.dropdown-submenu {
  position: relative;
}

.dropdown-submenu a::after {
  transform: rotate(-90deg);
  position: absolute;
  right: 6px;
  top: .8em;
}

.dropdown-submenu .dropdown-menu {
  top: 0;
  left: 100%;
  margin-left: .1rem;
  margin-right: .1rem;
}

и jQuery:

$('.dropdown-menu a.dropdown-toggle').on('click', function(e) {
    if (!$(this).next().hasClass('show')) {
        $(this).parents('.dropdown-menu').first().find('.show').removeClass("show");
    }
    var $subMenu = $(this).next(".dropdown-menu");
    $subMenu.toggleClass('show');
    $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function(e) {
        $('.dropdown-submenu .show').removeClass("show");
    });
    return false;
});
Ответ принят как подходящий

Я внес некоторые изменения в bootstrap 4.1.

<style type = "text/css">
    .navbar .dropdown-toggle, .navbar .dropdown-menu a {
        cursor: pointer;
    }

    .navbar .dropdown-item.active, .navbar .dropdown-item:active {
        color: inherit;
        text-decoration: none;
        background-color: inherit;
    }

    .navbar .dropdown-item:focus, .navbar .dropdown-item:hover {
        color: #16181b;
        text-decoration: none;
        background-color: #f8f9fa;
    }

    @media (min-width: 767px) {
        .navbar .dropdown-toggle:not(.nav-link)::after {
            display: inline-block;
            width: 0;
            height: 0;
            margin-left: .5em;
            vertical-align: 0;
            border-bottom: .3em solid transparent;
            border-top: .3em solid transparent;
            border-left: .3em solid;
        }
    }
</style>
<script type = "text/javascript">
    $(document).ready(function () {
        $('.navbar .dropdown-item').on('click', function (e) {
            var $el = $(this).children('.dropdown-toggle');
            var $parent = $el.offsetParent(".dropdown-menu");
            $(this).parent("li").toggleClass('open');

            if (!$parent.parent().hasClass('navbar-nav')) {
                if ($parent.hasClass('show')) {
                    $parent.removeClass('show');
                    $el.next().removeClass('show');
                    $el.next().css({"top": -999, "left": -999});
                } else {
                    $parent.parent().find('.show').removeClass('show');
                    $parent.addClass('show');
                    $el.next().addClass('show');
                    $el.next().css({"top": $el[0].offsetTop, "left": $parent.outerWidth() - 4});
                }
                e.preventDefault();
                e.stopPropagation();
            }
        });

        $('.navbar .dropdown').on('hidden.bs.dropdown', function () {
            $(this).find('li.dropdown').removeClass('show open');
            $(this).find('ul.dropdown-menu').removeClass('show open');
        });

    });
</script>

<?php function menu_builder1($db, $parent_id) {
    $sql = $db->prepare("SELECT * FROM menu WHERE status = 1 ORDER BY position ASC");
    if ($sql->execute()) {
        while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
            $array[$row['menu_sub_id']][] = $row;
        }
        main_menu1($array);
    }
}
function main_menu1($array, $parent_id = false) {
    if (!empty($array[$parent_id])) {
        foreach ($array[$parent_id] as $item) {
            if ($item['dropdown'] == false) {
                echo '<li class = "nav-item active"><a class = "nav-link" href = "' . $item['href'] . '">' . $item['name'] . '</a></li>';
            }
            elseif ($item['dropdown'] == true) {
                echo '<li class = "nav-item dropdown"><a class = "nav-link dropdown-toggle" id = "dropdown2" data-toggle = "dropdown" aria-haspopup = "true" aria-expanded = "false">' . $item['name'] . '</a>';
                sub_menu1($array, $item['menu_id']);
                echo '</li>';
            }
        }
    }
}
function sub_menu1($array = array(), $parent_id = false) {
    if (!empty($array[$parent_id])) {
        echo '<ul class = "dropdown-menu" aria-labelledby = "dropdown2">';
        foreach ($array[$parent_id] as $item) {
            if ($item['dropdown'] == false) {
                echo '<li class = "dropdown-item"><a href = "' . $item['href'] . '">' . $item['name'] . '</a></li>';
            }
            elseif ($item['dropdown'] == true) {
                echo '<li class = "dropdown-item dropdown"><a class = "dropdown-toggle" id = "dropdown2-1" data-toggle = "dropdown" aria-haspopup = "true" aria-expanded = "false">' . $item['name'] . '</a>';
                sub_sub_menu1($array, $item['menu_id']);
                echo '</li>';
            }
        }
        echo "</ul>";
    }
}

function sub_sub_menu1($array = array(), $parent_id = false) {
    if (!empty($array[$parent_id])) {
        echo '<ul class = "dropdown-menu" aria-labelledby = "dropdown2-1">';
        foreach ($array[$parent_id] as $item) {
            if ($item['dropdown'] == false) {
                echo '<li class = "dropdown-item"><a href = "' . $item['href'] . '">' . $item['name'] . '</a></li>';
            }
        }
        echo "</ul>";
    }
}
?>
<div class = "navbar navbar-expand-md navbar-dark bg-dark mb-4" role = "navigation">
    <button class = "navbar-toggler" type = "button" data-toggle = "collapse" data-target = "#navbarCollapse" aria-controls = "navbarCollapse" aria-expanded = "false" aria-label = "Toggle navigation">
        <span class = "navbar-toggler-icon"></span>
    </button>
    <div class = "collapse navbar-collapse" id = "navbarCollapse">
        <ul class = "navbar-nav mr-auto">
            <?=menu_builder1($db, 0)?>
        </ul>
    </div>
</div>

также некоторая информация по SQL

CREATE TABLE `menu` (
    `menu_id` int(11) NOT NULL,
    `menu_sub_id` int(11) NOT NULL,
    `added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `status` int(1) NOT NULL DEFAULT '1',
    `href` varchar(150) NOT NULL,
    `class` varchar(150) NOT NULL,
    `position` int(3) NOT NULL,
    `name` varchar(150) NOT NULL,
    `description` varchar(500) NOT NULL,
    `dropdown` int(11) NOT NULL,
    `sub_menu` int(1) NOT NULL,
    `sub_sub_menu` int(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `menu`
    ADD PRIMARY KEY (`menu_id`);

ALTER TABLE `menu` 
    MODIFY `menu_id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;

Другие вопросы по теме