Делаем табы на странице сайта на чистом JavaScript


1. Открываем свой любимый редактор кода и создаём новый файл с именем index.html
Это его базовая структура:

Код

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Табы на чистом JavaScript</title>
  <link href="https://fonts.googleapis.com/css?  
  family=Roboto:400,700&display=swap&subset=cyrillic" rel="stylesheet">
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <script src='js/script.js'></script>
</body>
</html>

В папке с проектом, где у вас сейчас находится файл index.html, создайте папки css и js, а в них файлы style.css и script.js соответственно.

Это код нашего файла со стилями style.css, он будет отвечать за оформление наших будущих табов:

Код

* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
}

img {
  max-width: 100%;
  height: auto;
  border-radius: 10px;
}

.fade {
  -webkit-animation-name: fade;
  animation-name: fade;
  -webkit-animation-duration: 2.5s;
  animation-duration: 2.5s;
  -webkit-animation-name: fade;
  -webkit-animation-duration: 2.5s;
  }
  @-webkit-keyframes fade {
  from {
  opacity: 0.1;
  }
  to {
  opacity: 1;
  }
  }
  @keyframes fade {
  from {
  opacity: 0.1;
  }
  to {
  opacity: 1;
  }
  }

.container {
  max-width: 500px;
  padding: 30px;
  margin: 30px;
  background-color: #eef1f4;
  color: #222222;
  font-weight: 400;
  border-radius: 10px;
}

.tabs_header {
  display: flex;
}

.title_header_tabs {
  padding: 3px 10px;
  margin-right: 10px;
  font-size: 20px;
  font-weight: 700;
  background-color: #95a5a6;
  color: #ffffff;
  border-radius: 5px;
  cursor: pointer;
}

.hide {
  display: none;
  }

.show {
  display: block;
  }

.active {
  background-color: #34495e;
  color: #ffffff;
  border: 2px solid #ffffff;
}

А в файле script.js мы с вами будем работать, писать наш скрипт, благодаря которому заработают наши вкладки.

Но прежде, чем приступать к написанию скрипта, давайте создадим HTML-структуру самих табов.
По логике: табы - это отдельные блоки кода, которые находятся внутри одного родительского контейнера, при этом изначально одна из вкладок активна и мы её видим на странице после загрузки, а другие вкладки скрыты.

Зададим контейнер для наших табов и присвоим ему класс .tabs

Код

<div class = "tabs"></div>

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

Давайте также сделаем этот блок с заголовками. Мы поместим его внутри нашего контейнера, присвоим ему класс .tabs_header:

Код

  <div class = "tabs">
  <div class="tabs_header">
  <div class="title_header_tabs active">Заголовок 1</div>
  <div class="title_header_tabs">Заголовок 2</div>
  <div class="title_header_tabs">Заголовок 3</div>
  </div>
  </div>

Внутри нашего блока с заголовками мы дополнительно создали три блока, каждый с классом .title_header_tabs. Это и будут заголовки наших вкладок, навигация.
Кроме того, для первого блока мы дополнительно задали класс .active, это позволит выделить заголовок активной вкладки среди остальных за счёт применения к нему определённых css-стилей.

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

Предлагаю следующую структуру:

- заголовок
- изображение
- какой-то текст

Код

<div class="tabContent fade">
  <h2>Заголовок</h2>
  <img src="здесь адрес изображения" alt="">
  <p>Здесь какой-то текст</p>
</div>

Таким образом, мы получим три отдельных блока с похожей структурой кода. Присвоим каждому из них класс .tabContent и дополнительно класс .fade (он нужен для анимации вкладок при переключении), блоки размещаем сразу после блока с заголовками табов:

Код

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Табы на чистом JavaScript</title>
  <link href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap&subset=cyrillic" rel="stylesheet">
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <div class = "tabs">

  <div class="tabs_header">
  <div class="title_header_tabs active">Заголовок 1</div>
  <div class="title_header_tabs">Заголовок 2</div>
  <div class="title_header_tabs">Заголовок 3</div>
  </div>

  <div class="tabContent fade">
  <h2>Первый</h2>
  <img src="здесь адрес изображения" alt="">
  <p>Здесь какой-то текст</p>
  </div>

  <div class="tabContent fade">
  <h2>Второй</h2>
  <img src="здесь адрес изображения" alt="">
  <p>Здесь какой-то текст</p>
  </div>

  <div class="tabContent fade">
  <h2>Третий</h2>
  <img src="здесь адрес изображения" alt="">
  <p>Здесь какой-то текст</p>
  </div>

  </div>

  <script src='js/script.js'></script>
</body>
</html>

На этом HTML-структура наших табов завершена, переходим в файл script.js для написания кода нашего скрипта.
Начнём с того, что для нашего глобального объекта window назначим обработчик события DOMContentLoaded, логика его такова: код JavaScript начнёт работу только после того как загрузится DOM-дерево страницы сайта, то есть весь HTML-код страницы:

Код

window.addEventListener('DOMContentLoaded', function() {

});

Вторым параметром мы передаём анонимную функцию, внутри которой мы и будем писать весь наш код.
Первая строка кода внутри этой функции переключает весь наш js-код в так называемый "строгий режим" use strict:

Код

window.addEventListener('DOMContentLoaded', function() {
  'use strict';
});


А теперь давайте подумаем, с чем нам придётся взаимодействовать в нашей программе, чтобы она работала?

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

Во-вторых, нам понадобится содержимое самих вкладок, и вот почему: для того, чтобы вкладки правильно работали, нам необходимо реализовать следующее: при активной(видимой) вкладке остальные должны быть скрыты.

Как мы знаем, чтобы производить какие-либо манипуляции с элементами страницы, их нужно предварительно выбрать.
Выбираем все заголовки с помощью метода querySelectorAll() и сохраняем в переменной tab:

Код

let tab = document.querySelectorAll('.title_header_tabs');

Выбираем также сам блок, содержащий в себе все заголовки табов(позднее станет понятно, для чего мы это сделали) и сохраняем в переменную info:

Код

let info = document.querySelector('.tabs_header');

Ну и, наконец, выбираем сами вкладки с контентом и сохраняем в переменной content:

Код

let content = document.querySelectorAll('.tabContent');

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

Итак, приступаем к написанию первой функции, назовём её hideTabContent:

Код

  function hideTabContent(a) {
  for (let i = a; i < content.length; i++) {
  content[i].classList.remove('show');
  content[i].classList.add('hide');
  tab[i].classList.remove('active');
  }
  }

Данной функции мы передаём один аргумент a, внутри функции мы помещаем цикл for, который будет проходить поочерёдно все выбранные вкладки(блоки с классом .tabContent) и скрывать их(удаляя класс .show и добавляя класс .hide)
Заодно удаляется класс .active, чтобы убрать выделение заголовка таба (оформление css-стилями.)

Так как на начальном этапе у нас активна первая вкладка табов, мы вызовем эту функцию, передав ей в качестве аргумента единицу, таким образом, цикл не коснётся первой вкладки(ведь её индекс 0, как вы помните, индексация элементов начинается с 0) и она будет активна и видима:

Код

hideTabContent(1);

Теперь напишем функцию, показывающую содержимое вкладок, назовём её showTabContent:

Код

  function showTabContent(b) {
  if(content[b].classList.contains('hide')) {
  content[b].classList.remove('hide');
  content[b].classList.add('show');
  tab[b].classList.add('active');
  }
  }

Данная функция принимает один аргумент, переменную b, и содержит условие, которое проверяет, если выбранная вкладка имеет класс .hide(вкладка скрыта), то функция удаляет этот класс и добавляет класс .show и класс .active

Теперь нам осталось назначить обработчик событий при клике по каждому из наших табов.
Здесь нам как раз и пригодится выбранный нами ранее блок с классом .tabs_header. Как вы помните, мы сохранили его в переменную info.
Имеено ей мы и назначим обработчик события:

Код

  info.addEventListener('click', function(event) {
  let target = event.target;
  if (target && target.classList.contains('title_header_tabs')) {
  for(let i = 0; i < tab.length; i++) {
  if (target == tab[i]) {
  hideTabContent(0);
  showTabContent(i);
  break;
  }
  }
  }
  });

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

В качестве события у нас будет click, а у функции в качестве аргумента будет объект события, event, чтобы мы могли сравнивать куда именно мы кликаем и в зависимости от этого производить какие-то действия.

В переменную target, созданную внутри функции, сохраняется именно тот элемент, на котором сработало событие(заметьте, не родительский элемент!)

А далее мы прописываем условие, которое проверяет, что если событие click имело место быть и что оно было в отношении именно элемента с классом title_header_tabs, то запускается цикл, в теле которого проверяется условие: если в переменной target сохранен элемент(вкладка) с определённым идентификатором, то все вкладки, начиная с первой, скрываются, а видимой становится вкладка с этим идентификатором.

Другими словами, если при переборе табов циклом совпадает таб, попавший в переменную target с табом, выбранным в данный момент циклом, то выполняется код функции.

На этом всё, а протестировать работу таких табов вы можете здесь.

Ссылка на GitHub

Комментарии к материалу: