Задать вопрос
@antonov_tag1

Как оптимально реализовать вкладки?

Надо записать компактно и более грамотно следующий код:

let tabOne = document.querySelector('#tab_one');
    let tabTwo = document.querySelector('#tab_two');

    tabBtnOne.addEventListener('click', function() {        
        tabOne.classList.add('open');
        tabTwo.classList.remove('open');
    });
    tabBtnTwo.addEventListener('click', function() {        
        tabOne.classList.remove('open');
        tabTwo.classList.add('open');
    });

Ведь вкладок может быть очень много, я понимаю, что есть более правильный подход, но не могу найти.
  • Вопрос задан
  • 322 просмотра
Подписаться 2 Простой 6 комментариев
Помогут разобраться в теме Все курсы
  • Нетология
    Веб-разработчик с нуля: профессия с выбором специализации
    14 месяцев
    Далее
  • Академия Эдюсон
    Fullstack-разработчик на JavaScript
    11 месяцев
    Далее
  • Skillbox
    JavaScript
    3 месяца
    Далее
Решения вопроса 2
Ankhena
@Ankhena Куратор тега JavaScript
Нежно люблю верстку
я понимаю что есть более правильный подход но не могу найти

Как вариант:

1. Вешаем слушатель событий на документ или родителя этих табов
2. Всем табам даем одинаковый класс
3. Проверяем попал ли таргет на таб
4. Всем убираем класс open
5. Тому, который в таргете задаем его

const CLASS_TAB = 'tab';
const CLASS_OPEN = 'open';

const block = document.querySelector('.block'); // родительский блок табов
const tabs = block.querySelectorAll(`.${CLASS_TAB}`);

block.addEventListener('click', ({target}) => {
  const tab = target.closest(`.${CLASS_TAB}`);
  if (tab) {
    tabs.forEach((item) => {
      item.classList.remove(CLASS_OPEN);
    });
    tab.classList.add(CLASS_OPEN);
  }
});


Условие тоже можно перезаписать компактнее, но мне кажется у вас вопрос как раз в логике кода, а не в сокращении символов.

На что-то такое
if (tab) tabs.forEach(t => t.classList.toggle('open', t === tab));


Когда дойдёте до задачи, когда нужно менять класс не самой кнопке-табу, а соответствующему блоку с контентом, то:
- Почитайте про DOM дерево, поиск родителей, соседей и т.д.
- Так же рекомендую использовать data-атрибуты для связи элементов.
Ответ написан
Mike_Ro
@Mike_Ro Куратор тега JavaScript
Python, JS, WordPress, SEO, Bots, Adversting
я понимаю что есть более правильный подход но не могу найти

Примеры из гугла, найти не проблема:
Табы (вкладки) для сайта на CSS и JavaScript – 3 с...
JS Горизонтальные вкладки
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
@UniInter
Можно удалить все пробелы (кроме после let) и вытянуть всё в одну строку.
Ответ написан
VoidVolker
@VoidVolker Куратор тега JavaScript
Dark side eye. А у нас печеньки! А у вас?
Вообще, поиск решения и оптимизация кода под задачи — это часть работы разработчика. Важно учиться делать это самостоятельно и приобретать опыт — это поможет в будущем при решении новых задачах. Если на каждую такую задачу бегать на форумы — вы ничему не научитесь.

Если хочется просто компактный и понятный код, который просто работает, то можно сделать например вот так:
let tabs = $('.tab') // Соответственно всем вкладкам добавить класс в разметке
tabs.on('click', function() {
    tabs.removeClass('open')
    this.addClass('open')
})

Да, будет дополнительная зависимость от JQuery или его любого аналога. Ну так оно для того и придумано.
А если совсем уходить в ООП, то можно сделать что-то типа такого:
class Tab {    
    constructor(container, id) {
        this.$ = $(container)
        this.$.data('id', id)
        this.id = id
    }

    on(event, xt) {
        this.$.on(event, xt)
        return this
    }

    onClick(xt) {
        this.on('click', xt)
        return this
    }
}

class Tabs {

    #openedClass = 'open'
    #defaultTabId = 0

    constructor(selector, openedTabId = defaultTabId) {
        this.selector = selector
        this.$ = $(selector)
        this.list = this.$.each((i, cnt) => this.tabInit(new Tab(cnt, i))).toArray()
        this.open(openedTabId)
    }

    tabInit(tab) {
        tab.onClick(() => this.open(tab.id))
        return this     
    }

    open(id) {
        for(const tab of this.list) {
            if (tab.id == id) {
                tab.$.addClass(openedClass)
            } else { 
                tab.$.removeClass(openedClass)
            }
        }
        return this
    }

    close(id) {
        for(const tab of this.list) {
            if (tab.id == id) {
                tab.$.removeClass(openedClass)
            } else { 
                tab.$.addClass(openedClass)
            }
        }
        return this
    }

    get opened() {
        return this.list.find((t) => t.$.hasClass(openedClass))
    }
}

Вот тут уже более высокий уровень абстракции и можно наращивать функционал в любую сторону по мере необходимости и без полного переписывания кода.
Ответ написан
Комментировать
@ImagineTables
Атрибутами в разметке, декларативно. Прописывать id в коде это в данном случае как программировать документ Word вместо написания.

Посмотрите, как это сделано в Bootstrap. Конкретно, на пример с табами. Не на имплементацию, а на подход.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы