Универсальное таб меню с вкладками.
Вступление.
В интернете можно найти достаточно много скриптов для управления меню на вкладках, написанных как на чистом JavaScript, так и на jQuery или с использованием его плагинов. К сожалению, большинство из них имеет достаточно большой недостаток, который заключается в том, что они не обладают большой гибкостью и универсальностью. Все вкладки связанны с открываемыми блоками через id
, href
и т.д. Добавление новых вкладок и соответствующих им блоков требует особого внимания, чтобы не запутаться в различных идентификаторах, особенно, если на странице несколько таких таб меню.
В этой статье мы подробно рассмотрим небольшой универсальный скрипт управления таб меню, написанный на ванильном JavaScript, который лишен перечисленных выше недостатков:
во-первых, отсутствие каких-либо идентификаторов;
во-вторых, гибкая связь между вкладкой (табом) и соответствующим ей блоком с контентом, основанная на навигации по DOM-элементам;
в-третьих, можно создавать сколько угодно таких меню с любым количеством вкладок (конечно, всё в пределах разумного).
HTML-разметка меню с табами.
Ниже представлена HTML-разметка меню, использующего табы. За основу меню взят немаркированный список <ul>
, а элементами управления будут <li>
. Использование <li>
в качестве интерактивного элемента устраняет ещё одну довольно распространённую ошибку — использование для этих целей тэга <a>
(ссылки).
Как с точки зрения семантики, так и с точки зрения СЕО — тэг
<a>
должен использоваться только для формирования ссылок, ведущих на другие страницы сайта или другой интернет-ресурс. Для управления элементами текущей страницы (показать / скрыть, изменить стиль, переместить, подгрузить и т.д.) должны использоваться элементы <span>
, <button>
, <div>
, <li>
. Именно на них вешаются обработчики событий.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<ul class="tabsmenu"> <li class="active">Вкладка 1</li> <li>Вкладка 2</li> <li>Вкладка 3</li> <li>Вкладка 4</li> </ul> <div class="container"> <div> <h3>Контейнер 1</h3> <p>Некий контент</p> </div> <div hidden> <h3>Контейнер 2</h3> <p>Некий контент</p> </div> <div hidden> <h3>Контейнер 3</h3> <p>Некий контент</p> </div> <div hidden> <h3>Контейнер 4</h3> <p>Некий контент</p> </div> </div> |
Как и писалось ранее, в вёрстке отсутствуют какие-либо идентификаторы элементов. При необходимости, можно без проблем добавить ещё несколько вкладок и блоков, которые они будут открывать. Даже можно добавить ещё одно таб меню и при этом не нужно беспокоиться об уникальности идентификаторов, обеспечивающих связь между вкладкой <li>
и соответствующим ей блоком <div>
.
Таблица стилей для меню с табами.
Представлены только стили, относящиеся непосредственно к сменю с вкладками:
Для уменьшения размера таблицы стилей, я не буду приводить свойства с вендорными префиксами, обеспечивающими кроссбраузерность. Не забывайте прописывать их при реализации своих проектов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
.tabsmenu { margin-bottom: -1px; } .tabsmenu li {width: 120px; height: 50px; display: flex; align-items: center; justify-content: center; font-size: 15px; color: #333; user-select:none; cursor: pointer; } .tabsmenu .active { color: #fff; border-radius: 5px 5px 0 0; background: #3b99fc; cursor: default; } .container > div { margin-bottom: 50px; padding: 20px; border: solid 1px #3b99fc; border-radius: 0 5px 5px 5px; } |
Если возникнет необходимость создать на этой странице ещё одно меню с вкладками, то достаточно продублировать HTML-разметку первого меню, изменив, естественно, контент блоков. При необходимости, можно изменить внешний вид нового таб меню, добавив ему класс .tabsmenu2
1 2 3 |
<ul class="tabsmenu tabsmenu2"></ul> |
Добавим в таблицу CSS стили для этого класса:
1 2 3 4 5 6 7 8 |
.tabsmenu2 .active { color: #3b99fc; border: solid 1px #3b99fc; border-bottom-color: #fff; background: #fff; } |
Пишем JavaScript для управления таб меню.
Для ограничения области видимости, разместим скрипт в анонимной самозапускающейся функции, чтобы не было конфликтов с другими JS-скриптами подключенными к странице.
1 2 3 4 5 6 |
;(function() { 'use strict'; })(); |
При написании JS-скрипта мы будем использовать конструкцию Class. Это позволит создать несколько экземпляров меню на вкладках на одной странице.
Создание экземпляров таб меню.
В-первую очередь, создадим коллекцию объектов всех таб меню, которые расположены на странице. Если на странице меню не окажется, то сделаем return
. Это необходимо для исключения ошибок и блокировки других скриптов JS, которые могут быть подключены к данной странице. Далее, с помощью метода for...of
переберём полученную коллекцию, при этом создавая экземпляры текущего меню с вкладками, используя конструктор класса Tabsmenu
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
;(function() { 'use strict'; class Tabsmenu { constructor(tabmenu) { } } // коллекция всех tab menu на странице const tabsmenu = document.querySelectorAll('.tabsmenu'); if (!tabsmenu) return; // перебираем полученную коллекцию for (let menu of tabsmenu) { // создаём экземпляр tab menu const tab = new Tabsmenu(menu); } })(); |
Весь дальнейший JS-код мы будем писать внутри конструкции class Tabsmenu { ... }
.
Прежде всего рассмотрим конструктор класса Tabsmenu
. Конструктор инициализирует ряд объектов и переменных, содержащих информацию об экземпляре таб меню. Кроме этого, в конструкторе зарегистрирован обработчик события, который будет срабатывать при клике по родительскому элементу таб меню. В качестве аргумента конструктор принимает объект tab menu, экземпляр которого создаётся в данный момент.
1 2 3 4 5 6 7 8 9 10 11 |
constructor(tabmenu) { this.tabmenu = tabmenu; // блоки с контентом для табов this.blocks = this.tabmenu.nextElementSibling.querySelectorAll('.container > div'); // коллекция табов this.tabs = this.tabmenu.querySelectorAll('li'); // вешаем обработчик событий на родительский элемент табов this.tabmenu.addEventListener('click', this.swithTab.bind(this)); } |
Переключение вкладок меню.
При срабатывании обработчика события, вызывается функция swithTab
. Алгоритм работы этой функции не сложен:
- убеждаемся, что клик сделан по элементу
<li>
, формирующим вкладку; - определяем индекс вкладки по которой был сделан клик;
- перебираем все вкладки текущего экземпляра таб меню и удаляем класс active;
- используя полученный индекс, делаем активной вкладку, по которой был клик;
- вызываем функцию переключения блоков с контентом
switchBloks
, передавая ей в качестве параметра индекс активной вкладки.
Код функции swithTab
и комментарии к нему:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
swithTab(e) { let target = e.target; // проверяем, по какому именно элементу таб меню был сделан клик // если клик был сделан не по вкладке, которая формируется тэгом <li>, // то прекращаем работу функции и переходим в ожидание следующего клика if (target.tagName !== 'LI') return; // индекс вкладки по которой был сделан клик const i = [].indexOf.call(this.tabs, target); // делаем вкладки неактивными for (let tab of this.tabs) { tab.classList.remove('active'); } // делаем активной вкладку, по которой был сделан клик this.tabs[i].classList.add('active'); this.switchBloks(i); } |
Переключение блоков с контентом.
Теперь рассмотрим подробнее функцию switchBlock
. Задачей данной функции является включение контейнера соответствующего активному табу и отключение всех остальных контейнеров. Код функции очень простой и в дополнительном разъяснении не нуждается:
1 2 3 4 5 6 7 8 9 10 |
switchBloks(i) { // делаем все блоки с контентом невидимыми for (let block of this.blocks) { block.hidden = true; } // делаем видимым блок контента, относящийся к активной вкладке this.blocks[i].hidden = false; } |
Заключение.
Как видно из статьи, вёрстка таб меню и скрипт управляющий его работой, достаточно простые. При необходимости данное меню легко расширяется. Можно добавить как новые вкладки и контейнеры с контентом, так и новое таб меню в целом.
Комментарии
-
Комментарии должны содержать вопросы и дополнения по статье, ответы на вопросы других пользователей.
Комментарии содержащие обсуждение политики, будут безжалостно удаляться. -
Для удобства чтения Вашего кода, не забываейте его форматировать. Вы его можете подсветить код с помощью тега
<pre>
:
—<pre class="lang:xhtml">
- HTML;
—<pre class="lang:css">
- CSS;
—<pre class="lang:javascript">
- JavaScript. - Если что-то не понятно в статье, постарайтесь указать более конкретно, что именно не понятно.