Pull to refresh

Модуль вкладок на es6/es2015 без jQuery и прочих зависимостей

Reading time3 min
Views13K

Предисловие


Какое-то время назад я стал постепенно отказываться от jQuery в пользу нативного javascript. Это связано с тем, что поддержка старых браузеров перестала быть приоритетной и на первое место вышла скорость загрузки страницы. Я не смог найти минималистичный модуль вкладок с простой html разметкой – поэтому решил написать свой.

Демо, Исходный код на Github

HTML разметка


<div class="tabs">
	<div class="tabs__toggle tabs__toggle_active">Вкладка 1</div>
	<div class="tabs__toggle">Вкладка 2</div>
	<div class="tabs__tab">
		Содержимое первой вкладки
	</div>
	<div class="tabs__tab">
		Содержимое второй вкладки
	</div>
</div>

Если на одной странице нужно разместить несколько групп вкладок нужно просто разделить их в разные блоки '.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

Спасибо за внимание!

P.S. Сделал опцию названия блока по _bem. Подробности в документации на гитхабе.
Tags:
Hubs:
+9
Comments13

Articles

Change theme settings