Табы на js, как правильно?

Полчаса назад кто-то задал вопрос (уже удалил), где показал код на JQ со своей тренировочной реализацией.
Я оставила комментарий, что не очень, т.к. зачем для таких простых вещей использовать JQuery. А потом поймала себя на мысли, что я никогда их на js сама и не делала))) Не приходилось, т.к. сама только учусь.

Повторю его вопрос, как делать правильно, чтобы легко было добавлять/поддерживать и т.п.

https://codepen.io/kris-iris/pen/ZqBEPv?editors=1010

Javascript для табов
class Tabs{
  constructor(){
    this.tabList = document.querySelectorAll('.pageNav__tabItem');
    this.contentList = document.querySelectorAll('.pageNav__contentItem');
    let nav = document.querySelector('.pageNav');
    
    nav.addEventListener('click', e => this.show(e));
    
    this.setIndex();
  }
  
  show(e){
    let t = e.target;
    if (!t.classList.contains('pageNav__tabItem')) return;
    
    this.removePrev();
    
    let index = t.getAttribute('data-index');
    let content = document.querySelector('.pageNav__contentItem[data-index="'+index+'"]');
    
    t.classList.add('pageNav__tabItem--active');
    content.classList.add('pageNav__contentItem--active');
  }
  
  setIndex(){
    for (let i = 0; i < this.tabList.length; i++){
      this.tabList[i].setAttribute('data-index', i);
      this.contentList[i].setAttribute('data-index', i);
    }
  }
  
  removePrev(){
    for (let i = 0; i < this.tabList.length; i++){
      this.tabList[i].classList.remove('pageNav__tabItem--active');
      this.contentList[i].classList.remove('pageNav__contentItem--active');
    }
  }
  
}

document.addEventListener('DOMContentLoaded', ()=>{
  let tabs = new Tabs();
})


Не откажусь от ссылки на пример хорошего кода!
  • Вопрос задан
  • 12201 просмотр
Решения вопроса 2
Самое первое - отказаться от неоправданного изменения html. Все эти `data-index` - признак плохого кода. Любой блок должен, по возможности, получаться в JS только один раз, записываться в кеш и работать далее с блоком именно как с JS инстансом.

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

Третье - изменения html максимально выносим в отдельный метод.

Ну и вообще - все действия разбить на блоки в виде методов.

Как разультат:

const TabItemSelector = '.pageNav__tabItem';
const ContentItemSelector = '.pageNav__contentItem';

class TabsManager {
  constructor(navNode){
    this.tabs = [];
    this.activeTab = null;

    this.initFromHtml(navNode);
    this.activateTab(this.tabs[0]);
  }

  initFromHtml (navNode) {
    const headers  = navNode.querySelectorAll(TabItemSelector);
    const contents = navNode.querySelectorAll(ContentItemSelector);

    for (var i = 0; i < headers.length; i++) {
        this.registerTab(headers[i], contents[i]);
    }
  }

  registerTab (header, content) {
    const tab = new TabItem(header, content);
    tab.onActivate(() => this.activateTab(tab));
    this.tabs.push(tab);
  }
  
  activateTab (tabItem) {
    if (this.activeTab) {
        this.activeTab.setActive(false);
    }

    this.activeTab = tabItem;
    this.activeTab.setActive(true);
  }
  
}

const ActiveTabHeaderClass = 'pageNav__tabItem--active';
const ActiveTabContentClass = 'pageNav__contentItem--active';

class TabItem {
    constructor (header, content) {
        this.header  = header;
        this.content = content;
    }
    onActivate (action) {
        this.header.addEventListener('click', () => action(this));
    }
    setActive(value) {
        this.header.classList.toggle(ActiveTabHeaderClass, value);
        this.content.classList.toggle(ActiveTabContentClass, value);
    }
}

document.addEventListener('DOMContentLoaded', ()=>{
  let tabs = new TabsManager(document.querySelector('.pageNav'));
})


Самое сомнительное в этом коде - это, конечно, TabsManager.initFromHtml, где создается взаимосвязь между headers и contents (к примеру, что будет если заголовков табов будет больше, чем детей?). Но это получается из-за верстки.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@TeteYang
const tbs = document.querySelector('.nav'),
tbsItem = document.querySelectorAll('.nav-item .nav-link'),
cardItm = document.querySelectorAll('.card-body'),
cardLay = document.querySelector('.card');

function dataId(){
for(let i = 0; i tbsItem[i].setAttribute('data-id', i);
cardItm[i].setAttribute('data-id', i);
}
}
dataId();

function showHide(b){
cardItm.forEach((item)=>{
item.classList.remove('active');
if(item.getAttribute('data-id') == b){
item.classList.add('active');
}
});
}
showHide();
function whereTab(e){
let target = e.target;
if(target.className == 'nav-link'){
let attrItem = target.getAttribute('data-id');
showHide(attrItem);
}
}
tbs.addEventListener('click', whereTab);
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы