Активное состояние элемента меню

У меня проблема с включением класса .active для каждого пункта меню, который я нажимаю на панели навигации моего веб-сайта (который построен на HTML, CSS, JS). Я использую файл nav.html для загрузки панели навигации на всех моих страницах с помощью этого кода:

<header id = "hero-header">
               <script>        AOS.init();
            </script>
    <div class = "logo-container">
        <a href = "home.html"><img class = "logo-desktop" id = "logo-hero" src = "assets/img/logo.svg"></a>
        <a href = "home.html"><img class = "logo-mobile" id = "logo-hero" src = "assets/img/mobile-logo.svg"></a>
    </div>

    <ul>
        
        <li data-aos = "fade-down" data-aos-duration = "600"><a href = "home.html" class = "menu-item-desktop">Home</a></li>
        <!-- <li data-aos = "fade-down" data-aos-duration = "600"><a href = "map.html" class = "">Map</a></li> -->
        <div data-aos = "fade-down" data-aos-duration = "800" class = "menu-item-desktop dropdown">
            <button class = "dropbtn">LifePulse ID</button>
            <div class = "dropdown-content">
                <a href = "before-donation.html">Before Donation</a>
                <a href = "after-donation.html">After Donation</a>
                <a href = "how-else-can-I-help.html" class = "">How else can I help</a>
            </div>
        </div>                    
        <li data-aos = "fade-down" data-aos-duration = "1000"><a href = "team.html" class = "menu-item-desktop">Team</a></li> 
        <li data-aos = "fade-down" data-aos-duration = "1000"><a href = "news.html" class = "menu-item-desktop ">News</a></li>
        <li data-aos = "fade-down" data-aos-duration = "1200"><a href = "partners.html" class = "menu-item-desktop ">Partners</a></li> 
        <li data-aos = "fade-down" data-aos-duration = "1400"><a href = "contact.html" class = "menu-item-desktop ">Contact</a></li>
        
        <div data-aos = "fade-down" data-aos-duration = "1600" class = "search-button">
            <form action = "/search">
                <input type = "search" name = "q" id = "search" placeholder = "Type and click enter">
                <a href = "#" id = "btn-close">
                    <span class = "fontawesome-close">
                        <i class = "fa-solid fa-times" style = "color: #ffffff;"></i>
                    </span>
                </a>
                <a href = "#" id = "btn-search">
                    <span class = "fontawesome-search">
                        <i class = "fa-solid fa-magnifying-glass" style = "color: #ffffff;"></i>
                    </span>
                </a>
            </form>
        </div>
    </ul>
    <div class = "button-container">
        <a href = "contact.html">
            <div class = "magnetic">
                <div class = "wrap">
                    <div class = "span span-1 go"></div>
                    <div class = "span span-2 go"></div>
                    <div class = "span span-3 go"></div>
                    <div class = "span span-4 go"></div>
                    <div class = "span span-1 go"></div>
                    <img src = "assets/img/hand.png">
                </div>
            </div>
        </a>
    </div>
</header> 

<div id = "hero-bottom">
    <div class = "city">Thessaloniki, GR</div>
    <ul>
        <a href = "https://www.instagram.com/lifepulse_gr" target = "_blank"><li><i class = "fa-brands fa-instagram " style = "color: #ffffff;"></i></li></a>
        <a href = "https://www.facebook.com/lifepulsegreece"  target = "_blank"><li><i class = " fa-brands fa-facebook-f social-icons fa-s" style = "color: #ffffff;"></i></li></a>
        <a href = "https://www.linkedin.com/company/lifepulse-blood-donation"  target = "_blank"><li><i class = "fa-brands fa-linkedin-in" style = "color: #ffffff;"></i></li></a>       
    </ul>
</div>

Я хочу, чтобы каждый раз, когда я нажимаю на пункт меню, этот конкретный элемент переходил в активное состояние. Я попытался создать файл menu.js с помощью этого кода:

const links =document.querySelectorAll(".menu-item-desktop ");
links.forEach(btn => btn.addEventListener("click",(e)=>{
     e.preventDefault();
     btn.classList.add("active")
  }));

и добавил его внизу тега body на каждой html-странице, но это не сработало. Что мне не хватает?

Пожалуйста, определите «это не сработало». Что не так с вашим текущим кодом?

Teemu 04.06.2024 10:44

Я использую файл nav.html для загрузки панели навигации на всех моих страницах. Как именно «загрузить nav.html на все ваши страницы»? Похоже, вы хотите запустить свой код после того, как это произойдет.

fdomn-m 04.06.2024 10:45

Что console.info(document.querySelectorAll(".menu-item-desktop").‌​length) дает вам?

fdomn-m 04.06.2024 10:45

@fdomn-m возвращает 6. Кроме того, что касается вашего другого вопроса, внутри тега body на каждой имеющейся у меня html-странице я использую: <script> $(function(){ $("#nav-placeholder").load( "нав.html"); </script> с соответствующим тегом div в качестве заполнителя, и меню загружается.

Panos Fusu 04.06.2024 10:48

6 — хорошо, если бы это было 0, код запустился бы слишком рано. Вы добавили это прямо перед const links= (то есть сделать console.info(links.length))? или вы запускали его в консоли после загрузки страницы?

fdomn-m 04.06.2024 10:59

@fdomn-m Я запустил его в консоли после загрузки страницы. Теперь я добавил его перед моим «constlinks=» и получил 0. Все еще получаю 6, если запустил его в консоли.

Panos Fusu 04.06.2024 11:09

Вероятно, вам придется подождать, пока документ будет проанализирован и DOM будет завершен. См. Документацию MDN — DOMContentLoaded. Вы также можете переместить JavaScript из вашего nav.html (вызов AOS.init()) в конец файла. Поможет ли это?

Peter Pointer 04.06.2024 11:27

Да, вы получаете 6, потому что это после запуска вашего сценария «загрузки заголовка». Сначала вы получаете 0, потому что код выполняется до загрузки заголовка — отсюда и просьба уточнить. Когда ваш код работает, верхний/нижний колонтитул не загружается. Вам необходимо переместить код обработчика событий в обратный вызов complete функции .load.

fdomn-m 04.06.2024 11:36

@PeterPointer К вашему сведению, ОП загружает навигацию с помощью $(function(){ $("#nav-placeholder").load("nav.html"); }); (см. комментарии)

fdomn-m 04.06.2024 11:46

@PanosFusu Пробовал мою версию?

Godot 04.06.2024 12:23

@Godot Да, но, к сожалению, пункты меню не переходят в активное состояние.

Panos Fusu 04.06.2024 12:34

@PanosFusu Извините, я делегировал полномочия не из того контейнера. Я обновил. Я не могу протестировать свой код, поскольку ни AJAX, ни localStorage не поддерживаются во фрагментах SO. Если вам действительно нужно, я могу посмеяться над чем-нибудь в jsfiddle.net.

Godot 04.06.2024 12:47

@Godot, только если у тебя есть время, так как речь идет о небольшом обновлении на моем сайте. Я наверняка сам делаю что-то не так, и это все равно не работает. Я использую предоставленный вами код как внутри тега сценария в конце тега body, так и в другом файле (menus.js), который я импортирую на свою html-страницу. Ничего из этого не помогло, но я опять же уверен, что делаю что-то не так.

Panos Fusu 04.06.2024 13:05

Посмотрите на мой ответ и скрипку

Godot 04.06.2024 13:57

Спасибо вам обоим за уделенное время! Мне удалось найти решение после некоторого изучения и подсказок gpt в чате. Благодарю вас <3

Panos Fusu 07.06.2024 07:33

Если какие-либо ответы вам помогли, не забудьте проголосовать за них.

fdomn-m 07.06.2024 08:12
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
16
105
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если вы хотите щелкнуть ссылки, которые заменяют страницу, на которой вы находитесь, на другую страницу, И чтобы элементы навигации были активны? Затем вам нужно сохранить то, что было нажато, в localStorage.

Альтернативно загрузите HTML-страницы по ссылкам, используя тот же метод .load, который вы используете для nav.html.

Если нет, используйте делегирование, потому что это более простой способ.

Вам нужно делегировать из ближайшего STATIC-контейнера - того, в который вы загружаете навигацию.

Кроме того, поскольку вы загружаете навигационное меню с помощью .load, вам нужен сценарий, который обрабатывает щелчки, чтобы НЕ находиться в этом файле, поскольку JS не будет запускаться на HTML-странице, загруженной с использованием AJAX (что и есть .load).

Этот код должен находиться на загружаемой вами странице (внешний скрипт подойдет), а не в nav.html.

Вот версия jQuery, которая загрузит делегат nav AND

https://jsfiddle.net/x6ourewL/1/

$(() => { // page loading
  const activeURL = localStorage.getItem('activeURL');
  const $container = $('#nav-placeholder')
  .load('nav.html', function() {
    // AOS.init(); // if that is needed in the nav
    $links = $('.menu-item-desktop a');
    console.info(activeURL, $(`[href = "${activeURL}"]`).attr('href'))
    $link = activeURL ? $(`[href = "${activeURL}"]`).eq(0) : $links.eq(0);
    $link.addClass('active'); // activate the first or first of found link (if that makes sense)
  }) 
  .on('click', '.menu-item-desktop a', function() { // delegation
    localStorage.setItem('activeURL',$(this).attr('href')); // before the link loads the new page
  });
});

Ваша проблема в том, что код обработчика событий запускается до загрузки элементов и, следовательно, не добавляет никаких событий.

У вас есть несколько вариантов:

  • добавьте код в .load complete обратный вызов
  • используйте делегирование событий (см. этот ответ (или более простой ответ jquery на этот вопрос, например, использование jquery)

Размещение кода обработчика событий внутри документа load/doc.ready не будет работать, поскольку он сработает до вашей вторичной загрузки.

Как указано в комментариях, ваш код в настоящее время (я предполагаю, что код события находится в doc.ready, не имеет значения)

$(function(){ 
    $("#nav-placeholder").load("nav.html"); 

    const links = document.querySelectorAll(".menu-item-desktop");
    links.forEach(btn => btn.addEventListener("click",(e)=>{
       e.preventDefault();
       btn.classList.add("active")
    }));
});

Измените это, чтобы добавить код события в обратный вызов загрузки:

$("#nav-placeholder").load("nav.html", function() {

    const links = document.querySelectorAll(".menu-item-desktop");
    links.forEach(btn => btn.addEventListener("click",(e)=>{
       e.preventDefault();
       btn.classList.add("active")
    }));
});


Делегирование событий будет осуществляться с использованием jquery, как вы использовали jquery для doc/ready и загрузки:

$(function(){ 
    $("#nav-placeholder").load("nav.html"); 

    $(document).on("click", ".menu-item-desktop", function(e) {
       e.preventDefault();
       $(".active").removeClass("active");
       $(this).addClass("active");
    });
});

Не могу не поблагодарить вас за вашу помощь и время! Подход делегирования событий в некоторой степени сработал: теперь все мои элементы переходят в активное состояние при нажатии (а когда я нажимаю на другой пункт меню, предыдущий активный элемент возвращается в состояние по умолчанию). Проблема этого кода в том, что ссылки не работают. Итак, я нажимаю на элемент, состояние меняется (СПАСИБО ЗА ЭТО <3), но я не перенаправляюсь на соответствующую страницу.

Panos Fusu 04.06.2024 12:06

"но меня не перенаправляют на соответствующую страницу" - это потому, что вы добавили e.preventDefault, который... предотвращает дефолтную (навигацию). Удалите эту строку, и ваш код начнет перемещаться. В этот момент новая страница не будет выделена, потому что это новая страница - в этот момент обратитесь к ответу @Godot, чтобы восстановить подсветку навигации при загрузке страницы. Но это не то, что спросили, а то, что будет, когда вы исправите то, что спросили. Примечание. Ответ @Godot необходимо будет применять в сочетании с этим ответом (в обратном вызове .load).

fdomn-m 04.06.2024 12:36

Ребята, я очень ценю время, которое вы потратили на мою проблему, я также очень удивлен тем, как быстро вы отвечаете. Мы (фактически вы) разобрались в причине моей проблемы (изменение активного состояния и нагрузка), и я уже узнал кое-что новое. Так что спасибо вам от всего сердца.

Panos Fusu 04.06.2024 12:38

@fdomn-m - позже я понял (из-за комментариев, опубликованных Panos), что навигация загружается в nav-placeholder - поэтому мой скрипт будет работать при делегировании из этого контейнера, без необходимости запуска в обратном вызове загрузки

Godot 04.06.2024 12:45
Ответ принят как подходящий

Что действительно сработало в конце, так это скрипт:

$(document).ready(function() {
                $("#nav-placeholder").load("nav.html", function() {
                    // Get current page URL
                    var url = window.location.pathname;
                    // Find the menu item that matches the current URL
                    $('#nav-placeholder a').each(function() {
                        if ($(this).attr('href') === url) {
                            $(this).addClass('active');
                        }
                    });
                });
            });

на всех моих html-страницах, чуть ниже

<div id = "nav-placeholder"></div>

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