Как убедиться, что при нажатии окрашивается только одна вкладка?

#javascript #html #css #bootstrap-4

#javascript #HTML #css #bootstrap-4

Вопрос:

Я пытаюсь написать такую функцию, чтобы при нажатии на вкладку (созданную с помощью bootstrap) она меняла цвет на золотой. Этот бит работает нормально, однако я хочу переключить активное свойство каждой вкладки (bootstrap), чтобы оно было включено для создания красивого белого контура. Проблема в том, что если вы снова не нажмете на ту же вкладку, она останется белой. Есть идеи? Спасибо.

Это моя работа до сих пор:

 let timesClicked = 1;

let navItems = document.querySelectorAll('.changeColor');
navItems.forEach(item => {
  item.addEventListener("click", () => {
    timesClicked  ;
    console.log(timesClicked);
    let previousItem = item;
    if (timesClicked % 2 == 0) {
      item.style.color = "#f0a500";
      item.classList.toggle('active');
      console.log(item);
    } else {
      previousItem.classList.toggle('active');
      console.log(previousItem);
    };

    navItems.forEach(otherItem => {
      if (otherItem !== item) {
        otherItem.style.color = "#1A1C20";
        /*
        item.addEventListener("click", () =>
          item.classList.toggle('active'));
       ;*/
      };
    });

  });
})  
 <!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<ul class="nav nav-tabs nav-fill justify-content-center mt-3" id="myTab" role="tablist">
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor active" id="mathematics-tab" data-toggle="tab" href="#Mathematics" role="tab"
      aria-controls="Mathematics" aria-selected="true">Mathematics</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="english-tab" data-toggle="tab" href="#profile" role="tab"
      aria-controls="profile" aria-selected="false">English</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="verbal-tab" data-toggle="tab" href="#contact" role="tab"
      aria-controls="contact" aria-selected="false">Verbal</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="nonverbal-tab" data-toggle="tab" href="#contact" role="tab"
      aria-controls="contact" aria-selected="false">Nonverbal</a>
  </li>
</ul>  

Ответ №1:

Основываясь на вашем коде, я выполнил следующие шаги, чтобы исправить это:

  1. перед щелчком установите первую вкладку активной по умолчанию.
  2. при нажатии на любую вкладку отключите предыдущую вкладку и запомните эту активную по переменной previousItem (вы должны объявить эту переменную вне forEach(..)).

 let navItems = document.querySelectorAll('.changeColor');
let previousItem = navItems[0];

navItems.forEach(item => {
  item.addEventListener("click", () => {

    if(previousItem == item)return;

    item.style.color = "#f0a500";
    item.classList.toggle('active');

    previousItem.classList.toggle('active');
    previousItem.style.color = "#1A1C20";

    previousItem = item;
 });
})  
 <!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<ul class="nav nav-tabs nav-fill justify-content-center mt-3" id="myTab" role="tablist">
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor active" id="mathematics-tab" data-toggle="tab" href="#Mathematics" role="tab"
      aria-controls="Mathematics" aria-selected="true" style="color:#f0a500;">Mathematics</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="english-tab" data-toggle="tab" href="#profile" role="tab"
      aria-controls="profile" aria-selected="false">English</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="verbal-tab" data-toggle="tab" href="#contact" role="tab"
      aria-controls="contact" aria-selected="false">Verbal</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="nonverbal-tab" data-toggle="tab" href="#contact" role="tab"
      aria-controls="contact" aria-selected="false">Nonverbal</a>
  </li>
</ul>  

Комментарии:

1. Спасибо! как вы добавили оператор return to if в одну строку? Т.е. какова логика?

2. это слишком сложно и требует дополнительных строк кода для достижения этого простого переключения меню. Смотрите мой ответ. Также, пожалуйста, добавьте подробности в свой ответ для других читателей.

3. @github292929 это короткий способ написания оператора if if(previousItem == item){return;} , когда у вас есть только одна строка в фигурной скобке, вы можете обойтись без фигурной скобки.

4. @AlwaysHelping спасибо за напоминание, я только что добавил детали, и это не слишком сложно, вы можете видеть, что я сохранил console.logs and timesClicked , поэтому OP может видеть разницу, ваш ответ отличный! но нужно ли повторять все вкладки каждый раз, когда вы нажимаете?

5. @QiuZhou спасибо. Я не думаю, что это излишне, и при этом нет проблем с производительностью, поскольку цель состоит в том, чтобы писать МЕНЬШЕ кода, но всегда достигать одинаковых результатов.

Ответ №2:

Вы слишком усложняете code , это можно просто сделать, используя querySelectorAll forEach метод and .

Просто удалите active класс и color из всех nav items , а затем добавьте только в clicked пункт меню, используя только метод Event.target

Упрощенная демонстрация кода:

 let navItems = document.querySelectorAll('.changeColor');
navItems.forEach(item => {
  item.addEventListener("click", (e) => {
    navItems.forEach(otherItem => {
      otherItem.style.color = "#1A1C20";
      otherItem.classList.remove('active');
    });
    e.target.classList.add('active');
    e.target.style.color = "#f0a500";
  });
})  
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<ul class="nav nav-tabs nav-fill justify-content-center mt-3" id="myTab" role="tablist">
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor active" id="mathematics-tab" data-toggle="tab" href="#Mathematics" role="tab" aria-controls="Mathematics" aria-selected="true">Mathematics</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="english-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">English</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="verbal-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Verbal</a>
  </li>
  <li class="nav-item" role="presentation">
    <a class="nav-link changeColor black-text-start" id="nonverbal-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Nonverbal</a>
  </li>
</ul>  

Комментарии:

1. спасибо за это, но зачем вам это делать: e.target.classList.remove(‘active’); . Разве это не просто удаляет активный переключатель при каждом нажатии на вкладку?

2. @github292929 нет проблем 🙂 e.target гарантирует, что мы добавим только к выбранному элементу. и извините, что опечатка. это должно быть e.target.classList.add('active'); add, а не remove.

3. Теперь это имеет большой смысл, мне просто интересно, когда будет указан otherItem? В моем коде другие элементы определяются как те != item — просто запутался в этом бите. Спасибо, и я приму ваш ответ.

4. @github292929 конечно, позвольте мне уточнить. Otheritem происходит из forEach цикла, который находится внутри click функции. Он запускается только тогда, когда мы нажимаем на вкладку, он удаляет все цвета и активные классы для каждого li элемента, а затем e.target добавляет цвет и класс только для выбранного элемента.

5. извините, позвольте мне уточнить, мне просто интересно, как цикл forEach узнает, что Otheritem отличается от item ? Спасибо

Ответ №3:

Это мое решение вашей проблемы

 let navItem = document.querySelectorAll('.changeColor');
function someFunction({ target }) {
  navItem.forEach((element) => {
    element.style.color = '#1A1C20';
    element.classList.remove('active');
  });
  target.style.color = '#f0a500';
  target.classList.toggle('active');
}
navItem.forEach((element) => {
  element.addEventListener('click', (e) => someFunction(e));
});