[Из песочницы] Модуль вкладок на es6/es2015 без jQuery и прочих зависимостей
Предисловие
Какое-то время назад я стал постепенно отказываться от jQuery в пользу нативного javascript. Это связано с тем, что поддержка старых браузеров перестала быть приоритетной и на первое место вышла скорость загрузки страницы. Я не смог найти минималистичный модуль вкладок с простой html разметкой — поэтому решил написать свой.
Демо, Исходный код на Github
HTML разметка
Вкладка 1
Вкладка 2
Содержимое первой вкладки
Содержимое второй вкладки
Если на одной странице нужно разместить несколько групп вкладок нужно просто разделить их в разные блоки '.tabs'. Расположение внутренних блоков влияет только на порядок их вывода. Вкладке по умолчанию следует добавить класс 'tabs__toggle_active'.
Класс закладки
class Tab {
constructor (tabs, toggle, tab) {
this.tabs = tabs;
this.toggle = toggle;
this.tab = tab;
this.init();
}
init () {
if (this.toggle.classList.contains('tabs__toggle_active')) {
this.open();
} else {
this.close();
}
this.toggle.addEventListener('click', () => {
this.open();
});
}
open () {
if (this.tabs.active === this) {
// already open
return;
}
if (this.tabs.active) {
this.tabs.active.close();
}
this.tabs.active = this;
this.tab.style.display = 'block';
this.toggle.classList.add('tabs__toggle_active');
}
close () {
this.tab.style.display = 'none';
this.toggle.classList.remove('tabs__toggle_active');
}
}
Конструктор принимает родительский класс группы вкладок, DOM элемент кнопки по которой открывается вкладка и DOM вкладки, к которой относится данная кнопка.
Функция init проверяет, является ли эта вкладка открытой по умолчанию и добавляет событие открытия по клику.
Функция open закрывает открытую вкладку при ее наличии и устанавливает ссылку на собственный экземпляр класса в свойство 'active' родительского класса. Так же проставляет активный класс для стилизации кнопки и свойство 'display' вкладки.
Функция close убирает активный класс с кнопки и скрывает вкладку.
Класс группы вкладок
export class Tabs {
constructor (container) {
this.container = container;
this.init();
}
init () {
this.toggles = this.container.querySelectorAll('.tabs__toggle');
this.tabs = this.container.querySelectorAll('.tabs__tab');
if (!this.isEverythingOk()) {
return;
}
for (let index = 0; index < this.toggles.length; index++) {
new Tab (this, this.toggles[index], this.tabs[index]);
}
}
isEverythingOk () {
if (this.toggles.length !== this.tabs.length) {
console.warn('Tabs toggles and tabs amounts are not matching');
return false;
} else if (this.toggles.length === 0) {
console.warn('There\'s no toggles for tabs');
return false;
} else if (this.tabs.length === 0) {
console.warn('There\'s no content tabs');
return false;
}
return true;
}
}
Конструктор принимает DOM объект группы вкладок (в нашем случае .tabs).
Функция init проходит циклом по всем кнопкам и создает экземпляры класса Tab группируя по принципу «первая кнопка к первой вкладке».
Функция isEverythingOk проверяет соответствие количества вкладок количеству кнопок и их наличие, в противном случае выбрасывает предупреждение в консоль для более удобного поиска ошибок.
Функция инициализации
export default function initTabs(selector) {
for (let container of document.querySelectorAll(selector)) {
new Tabs(container);
}
}
Функция предназначена для тех, кто не хочет разбираться с принципами работы с DOM или же просто для удобства. Создает экземпляры класса Tabs.
Пример с использованием функции инициализации
import initTabs from 'future-tabs';
initTabs('.tabs');
Пример работы напрямую с классом
import {Tabs} from 'future-tabs';
const container = document.querySelector('.tabs');
const tabs = new Tabs(container);
В планах сделать выборку внутренних блоков в зависимости от селектора, дописывая названия элементов следуя методологии _bem.
Github
Спасибо за внимание!