Как избежать вложенных циклов forEach для этого сценария содержимого с вкладками?

Я написал небольшой скрипт на JavaScript для содержимого вкладок.

(function() {
  let contentElms = document.querySelectorAll('.content > div');
  let tabs = document.querySelectorAll('.tabs li');

  // Show first tab initially
  contentElms[0].classList.add("active");
  tabs.forEach((tab, index) => {
    tab.addEventListener("click", () => {
      // Toggle tabs
      tabs.forEach((tab) => {
        tab.classList.remove("active")
      });
      tab.classList.add("active");

      // Toggle content
      contentElms.forEach((el) => {
        el.classList.remove("active")
      });

      contentElms[index].classList.add("active");
    });
  });
})();
body {
     margin: 0;
     padding: 0;
     font-family: Arial, Helvetica, sans-serif;
}
 body * {
     box-sizing: content-box;
}
 .tabbed-content {
     max-width: 600px;
     margin: 10px auto;
}
 .tabbed-content .tabs ul {
     list-style-type: none;
     margin: 0;
     padding: 0;
     display: flex;
}
 .tabbed-content .tabs ul li {
     flex: 1;
     border: 1px solid rgba(0, 0, 0, 0.1);
     border-radius: 4px 4px 0 0;
     overflow: hidden;
}
 .tabbed-content .tabs ul li.active {
     border-bottom: none;
     font-weight: bold;
}
 .tabbed-content .tabs ul a {
     display: block;
     padding: 10px;
     text-align: center;
     text-decoration: none;
     color: #7f7f7f;
}
 .tabbed-content .content {
     padding: 10px;
     border: 1px solid rgba(0, 0, 0, 0.1);
     border-top: none;
     border-radius: 0 0 4px 4px;
}
 .tabbed-content .content > div {
     font-size: 14px;
     line-height: 1.5;
     text-align: justify;
     display: none;
}
 .tabbed-content .content > div.active {
     display: block;
}
 
<div class = "tabbed-content">
  <nav class = "tabs">
    <ul>
      <li class = "active"><a href = "#">Tab 1</a></li>
      <li><a href = "#">Tab 2</a></li>
      <li><a href = "#">Tab 3</a></li>
    </ul>
  </nav>
  <div class = "content">
    <div>Nesciunt velit a hic, officia animi veritatis quis obcaecati tempora omnis iusto.</div>
    <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Molestias dolorem, sequi quos unde tempora corporis voluptatibus officia atque voluptatum consequuntur necessitatibus fuga quidem nihil. Perspiciatis reiciendis impedit cupiditate odit veritatis!</div>
    <div>Deserunt est in, ipsum possimus dolorum! Numquam suscipit laborum, reiciendis delectus. Labore?</div>
  </div>
</div>

Вкладки работают нормально.

Проблема

Меня не устраивает тот факт, что в скрипте есть вложенные forEach циклы.

Вопросы

  1. Есть ли (надежный) способ избежать этого?
  2. Могу ли я использовать в сценарии только один цикл forEach?

Да, никаких петель вообще не нужно. Используйте делегирование событий и сохраните текущую активную вкладку в переменную.

Teemu 28.08.2024 10:37

Какие вложенные циклы вас беспокоят? Цикл верхнего уровня просто назначает обработчик кликов для каждой вкладки. Каждый обработчик кликов не имеет вложенных циклов, только два цикла верхнего уровня для установки класса active.

Wiktor Zychla 28.08.2024 10:41

@WiktorZychla Могу ли я использовать в сценарии только один цикл forEach?

Razvan Zamfir 28.08.2024 10:42
Поведение ключевого слова "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) для оценки ваших знаний,...
0
3
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ага. Вы можете использовать этот код

Вместо циклов мы будем сохранять ссылки на активный контент и элементы вкладок и обновлять их при нажатии.

(function() {
  let contentElms = document.querySelectorAll('.content > div');
  let tabs = document.querySelectorAll('.tabs li');

  // Show first tab initially
  contentElms[0].classList.add("active");
  tabs[0].classList.add("active");
  let contentActive = contentElms[0]
  let tabActive = tabs[0]
  tabs.forEach((tab, index) => {
    tab.addEventListener("click", () => {
      contentActive.classList.remove("active")
      contentActive = contentElms[index]
      contentActive.classList.add("active")

      tabActive.classList.remove("active")
      tabActive = tab
      tabActive.classList.add("active")
    });
  });
})();
body {
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica, sans-serif;
}

body * {
  box-sizing: content-box;
}

.tabbed-content {
  max-width: 600px;
  margin: 10px auto;
}

.tabbed-content .tabs ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  display: flex;
}

.tabbed-content .tabs ul li {
  flex: 1;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 4px 4px 0 0;
  overflow: hidden;
}

.tabbed-content .tabs ul li.active {
  border-bottom: none;
  font-weight: bold;
}

.tabbed-content .tabs ul a {
  display: block;
  padding: 10px;
  text-align: center;
  text-decoration: none;
  color: #7f7f7f;
}

.tabbed-content .content {
  padding: 10px;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-top: none;
  border-radius: 0 0 4px 4px;
}

.tabbed-content .content>div {
  font-size: 14px;
  line-height: 1.5;
  text-align: justify;
  display: none;
}

.tabbed-content .content>div.active {
  display: block;
}
<div class = "tabbed-content">
  <nav class = "tabs">
    <ul>
      <li class = "active"><a href = "#">Tab 1</a></li>
      <li><a href = "#">Tab 2</a></li>
      <li><a href = "#">Tab 3</a></li>
    </ul>
  </nav>
  <div class = "content">
    <div>Nesciunt velit a hic, officia animi veritatis quis obcaecati tempora omnis iusto.</div>
    <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Molestias dolorem, sequi quos unde tempora corporis voluptatibus officia atque voluptatum consequuntur necessitatibus fuga quidem nihil. Perspiciatis reiciendis impedit cupiditate odit veritatis!</div>
    <div>Deserunt est in, ipsum possimus dolorum! Numquam suscipit laborum, reiciendis delectus. Labore?</div>
  </div>
</div>

Он не добавляет/удаляет класс «активный» на вкладках.

Razvan Zamfir 28.08.2024 10:53

Хотели бы немного объяснить ваш код, чтобы сообщить ОП, где он сделал ошибку?

Nijat Mursali 28.08.2024 10:53

@RazvanZamfir все получится

Tachibana Shin 28.08.2024 11:01

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

(function() {
  let contentElms = document.querySelectorAll('.content > div');
  let tabsContainer = document.querySelector('.tabs');

  // Show first tab initially
  contentElms[0].classList.add("active");
  tabsContainer.querySelector('li').classList.add("active");

  // Use event delegation
  tabsContainer.addEventListener("click", (event) => {
    let tab = event.target.closest('li');
    
    if (tab) {
      let index = Array.from(tabsContainer.querySelectorAll('li')).indexOf(tab);

      // Remove active class from all tabs and content
      tabsContainer.querySelectorAll('li').forEach(tab => tab.classList.remove("active"));
      contentElms.forEach(el => el.classList.remove("active"));

      // Add active class to the clicked tab and corresponding content
      tab.classList.add("active");
      contentElms[index].classList.add("active");
    }
  });
})();
body {
     margin: 0;
     padding: 0;
     font-family: Arial, Helvetica, sans-serif;
}
 body * {
     box-sizing: content-box;
}
 .tabbed-content {
     max-width: 600px;
     margin: 10px auto;
}
 .tabbed-content .tabs ul {
     list-style-type: none;
     margin: 0;
     padding: 0;
     display: flex;
}
 .tabbed-content .tabs ul li {
     flex: 1;
     border: 1px solid rgba(0, 0, 0, 0.1);
     border-radius: 4px 4px 0 0;
     overflow: hidden;
}
 .tabbed-content .tabs ul li.active {
     border-bottom: none;
     font-weight: bold;
}
 .tabbed-content .tabs ul a {
     display: block;
     padding: 10px;
     text-align: center;
     text-decoration: none;
     color: #7f7f7f;
}
 .tabbed-content .content {
     padding: 10px;
     border: 1px solid rgba(0, 0, 0, 0.1);
     border-top: none;
     border-radius: 0 0 4px 4px;
}
 .tabbed-content .content > div {
     font-size: 14px;
     line-height: 1.5;
     text-align: justify;
     display: none;
}
 .tabbed-content .content > div.active {
     display: block;
}
<div class = "tabbed-content">
  <nav class = "tabs">
    <ul>
      <li class = "active"><a href = "#">Tab 1</a></li>
      <li><a href = "#">Tab 2</a></li>
      <li><a href = "#">Tab 3</a></li>
    </ul>
  </nav>
  <div class = "content">
    <div>Nesciunt velit a hic, officia animi veritatis quis obcaecati tempora omnis iusto.</div>
    <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Molestias dolorem, sequi quos unde tempora corporis voluptatibus officia atque voluptatum consequuntur necessitatibus fuga quidem nihil. Perspiciatis reiciendis impedit cupiditate odit veritatis!</div>
    <div>Deserunt est in, ipsum possimus dolorum! Numquam suscipit laborum, reiciendis delectus. Labore?</div>
  </div>
</div>

Итак, tabsContainer (родительский элемент всех вкладок) прослушивает события кликов. При щелчке проверяется, является ли цель (event.target) вкладкой (li). Затем индекс выбранной вкладки определяется путем преобразования NodeList вкладок в массив с помощью Array.from и использования indexOf для поиска индекса. Наконец, из всех вкладок и элементов контента сначала удаляется класс active. Затем выбранная вкладка и соответствующий контент становятся активными.

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

Nijat Mursali 28.08.2024 11:14

временная сложность"??? Действительно? Вы ожидаете миллионы вкладок?

jabaa 28.08.2024 11:15

@jabaa извини, но как человека, обладающего знаниями в области искусственного интеллекта, меня волнует временная сложность всего. :)

Nijat Mursali 28.08.2024 11:16

Похоже, вы не понимаете временную сложность, если вы думаете, в данном случае об этом следует упомянуть. В случаях с небольшими n временная сложность не имеет значения. Худшая временная сложность может быть быстрее, чем лучшая временная сложность.

jabaa 28.08.2024 11:17

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