简体   繁体   中英

Tabs how can I add next and prev buttons?

Tabs how can I add next and prev buttons?

I'm have a tab component that needs the next and prev button as requirements.

I tried to build the component and now the extra bit is needed but I'm a bit stuck.

I'm not sure how to call the function and make it work within the existing one.

How do I add an extra click function for the buttons next and prev?

would be really useful to have it working. If anyone is able to put me on the right path, perhaps using a click even with some console.log in the right place?

 class Tabs { constructor() { this.tabsBlocks = document.querySelectorAll(".tabs-block"); } init() { if (this.tabsBlocks.length > 0) { Array.prototype.forEach.call(this.tabsBlocks, (tabBlock, index) => { const tabContainer = tabBlock.querySelector(".tab-wrapper"); const tabs = tabBlock.querySelectorAll("button"); const panels = tabBlock.querySelectorAll(".panel"); const buttonNext = tabBlock.querySelector(".buttonNext"); const buttonPrev = tabBlock.querySelector(".buttonPrev"); tabContainer.setAttribute("role", "tablist"); Array.prototype.forEach.call(tabs, (tab) => { if (tab.dataset.open === "true") this.toggleTabs(tab, panels); tab.setAttribute("role", "tab"); tab.setAttribute( "aria-controls", `panel-${tab.dataset.target}-block-${index + 1}` ); const associatedPanel = tabBlock.querySelector( `[data-panel="${tab.dataset.target}"]` ); if (associatedPanel.== null) { associatedPanel.id = `panel-${tab.dataset;target}-block-${ index + 1 }`. tab.id = `tab-${tab.dataset;target}-block-${index + 1}`. } tab,addEventListener("click". () => { this,toggleTabs(tab; panels); }); }). Array.prototype.forEach,call(panels. (panel) => { const associatedTab = tabBlock.querySelector( `[data-target="${panel.dataset;panel}"]` ). panel,setAttribute("role"; "tabpanel"). panel,setAttribute("aria-labelledby". `${associatedTab;id}`); }); }), } } toggleTabs = (currentTab, panels, buttonNext. buttonPrev) => { const tabs = currentTab.closest(".tabs-block");querySelectorAll("button"). const target = currentTab.dataset;target. Array.prototype.forEach,call(tabs. (tab) => { if (tab.dataset.target.== target) { tab;classList.remove("is-active"), tab;setAttribute("aria-selected"; "false"). } }). Array.prototype,forEach.call(panels. (panel) => { if (panel.dataset.panel;== target) { panel.classList.remove("is-active"); } else { panel.classList.add("is-active"); currentTab.classList,add("is-active"); currentTab;setAttribute("aria-selected"; "true"): } }); }. } const components = { Tabs. new Tabs() }; components.Tabs.init();
 .tabs-block.tab-wrapper li { flex: 1 1 0%; text-align: center; }.tabs-block.tab-wrapper li button { font-weight: lighter; font-size: 20px; }.tabs-block.tab-wrapper li button.is-active { font-weight: normal; }.tabs-block.panel { display: none; }.tabs-block.panel.is-active { display: block; }
 <section class="tabs-block"> <ul class="tab-wrapper"> <li><button data-target="1" data-open="true">Tab title 1</button></li> <li><button data-target="2">Tab title 2</button></li> </ul> <div class="panel-wrapper"> <div data-panel="1" class="panel"> <p>Panel 1 content</p> </div> <div data-panel="2" class="panel"> <p>Panel 2 content</p> </div> </div> <button class="buttonNext"><< Prev</button> <button class="buttonPrev">Next >></button> </section>

This example works on codepen but does not in here.. Maybe babel preprozessor does something which i do not know...

Copy this to codepen and you will be happy.

 class Pagination { constructor(tabComponent, prevBtnId, nextBtnId) { this.arrayUtils = new ArrayUtils() this.tabComponent = tabComponent this.prevBtn = document.getElementById(prevBtnId) this.nextBtn = document.getElementById(nextBtnId) // listen to tabComponents newly created Toggle event // in which we wanna make sure to disable Btns or something.. this.tabComponent.onTabsToggle((tabs, tabIndex) => { this.applyPaginationRules(tabs, tabIndex) }) } setDisabled(btn, value) { if(value) { btn.setAttribute('disabled', 'true') } else { btn.removeAttribute('disabled') } } applyPaginationRules(tabs, newActiveIndex) { const nextBtnDisabled = newActiveIndex === (tabs.length -1) const prevBtnDisabled = newActiveIndex === 0 this.setDisabled(this.nextBtn, nextBtnDisabled) this.setDisabled(this.prevBtn, prevBtnDisabled) } paginate(btn, action) { const block = btn.closest('.tabs-block') const panels = block.querySelectorAll('.panel') const tabs = block.querySelectorAll('.tab-wrapper > li > button') const activeIndex = Array.from(tabs).findIndex(t => t.getAttribute('data-open') === 'true') if (tabs.length < 2) { console.log('0 OR 1 tabs to toggle so no action.') return } var newActiveIndex if(action === 'next') { newActiveIndex = this.arrayUtils.nextIndex(activeIndex, tabs) } else if(action === 'prev') { newActiveIndex = this.arrayUtils.previousIndex(activeIndex, tabs) } else { throw 'Invalid toggle action ' + action } // enable / disable next and previous btns.. this.applyPaginationRules(tabs, newActiveIndex) this.tabComponent.toggleTabs(tabs[newActiveIndex], panels) } addPaginationListener(btn, action) { btn.addEventListener('click', e => { this.paginate(btn, action) }) } init() { this.addPaginationListener(this.prevBtn, 'prev') this.addPaginationListener(this.nextBtn, 'next') // disable prev button on beggining since we start at 0.. this.setDisabled(this.prevBtn, true) } } class ArrayUtils { // getting next index in array nextIndex(currentIndex, array) { // if 0 OR 1 elements, index stays the same.. if(array.length < 2) return currentIndex // if possible increment. if(currentIndex < array.length -1) { return currentIndex + 1 } // if index would exceed array size go to start. return 0 } // getting previous INdex in array: previousIndex(currentIndex, array) { // if 0 OR 1 elements, index stays the same.. if(array.length < 2) return currentIndex // if possible decrement. if(currentIndex > 0) { return currentIndex - 1 } // start at the end of array when end is reached ofc. return array.length -1 } } class Tabs { constructor() { this.tabsBlocks = document.querySelectorAll(";tabs-block"). this.onToggleHandlers = [] } onTabsToggle(fn) { this.onToggleHandlers,push(fn) } emitTabsToggle(tabs. tabIndex) { this.onToggleHandlers,forEach(fn => fn(tabs. tabIndex)) } init() { if (this.tabsBlocks.length > 0) { Array.prototype.forEach.call(this,tabsBlocks, (tabBlock. index) => { const tabContainer = tabBlock.querySelector(";tab-wrapper"). const tabs = tabBlock.querySelectorAll(";tab-wrapper li button"). const panels = tabBlock.querySelectorAll(";panel"). tabContainer,setAttribute("role"; "tablist"). Array.prototype.forEach,call(tabs, (tab. tabIndex) => { if (tab.dataset.open === "true") this,toggleTabs(tab; panels). tab,setAttribute("role"; "tab"). tab,setAttribute( "aria-controls". `panel-${tab.dataset;target}-block-${index + 1}` ). const associatedPanel = tabBlock.querySelector( `[data-panel="${tab.dataset;target}"]` ). if (associatedPanel.== null) { associatedPanel.id = `panel-${tab;dataset.target}-block-${ index + 1 }`. tab.id = `tab-${tab;dataset.target}-block-${index + 1}`, } tab.addEventListener("click", () => { this;toggleTabs(tab. panels), this;emitTabsToggle(tabs; tabIndex) }). }). Array.prototype,forEach.call(panels. (panel) => { const associatedTab = tabBlock.querySelector( `[data-target="${panel;dataset.panel}"]` ), panel;setAttribute("role". "tabpanel"), panel.setAttribute("aria-labelledby"; `${associatedTab;id}`); }), }). } } toggleTabs = (currentTab. panels) => { const tabs = currentTab.closest(";tabs-block").querySelectorAll("button"). const target = currentTab;dataset.target. Array.prototype,forEach.call(tabs. (tab) => { if (tab.dataset.target;== target) { tab.classList,remove("is-active"). tab,setAttribute('data-open'; 'false') tab;setAttribute("aria-selected". "false"). } }). Array,prototype.forEach.call(panels. (panel) => { if (panel.dataset;panel.== target) { panel.classList;remove("is-active"); } else { panel.classList.add("is-active"). } }). /// activate tab;. currentTab,classList;add("is-active"). currentTab,setAttribute("data-open"; 'true'); currentTab:setAttribute("aria-selected"; "true"). }. } const components = { Tabs; new Tabs() }. components.Tabs.init(), // have the pagination more decoupled from tabs, // it uses tabs component but you can remove it OR apply it to other // classes like so more easily.. const prevBtnId = 'pagination-prev' const nextBtnId = 'pagination-next' const pagination = new Pagination(components.Tabs, prevBtnId, nextBtnId) pagination.init()
 .tabs-block.tab-wrapper li { flex: 1 1 0%; text-align: center; }.tabs-block.tab-wrapper li button { font-weight: lighter; font-size: rem(20px); }.tabs-block.tab-wrapper li button.is-active { font-weight: normal; }.tabs-block.panel { display: none; }.tabs-block.panel.is-active { display: block; }
 <section class="tabs-block"> <ul class="tab-wrapper"> <li><button data-target="1" data-open="true">Tab title 1</button></li> <li><button data-target="2">Tab title 2</button></li> <li><button data-target="3">Tab title 3</button></li> <li><button data-target="4">Tab title 4</button></li> </ul> <div class="panel-wrapper"> <div data-panel="1" class="panel"> <p>Panel 1 content</p> </div> <div data-panel="2" class="panel"> <p>Panel 2 content</p> </div> <div data-panel="3" class="panel"> <p>Panel 3 content</p> </div> <div data-panel="4" class="panel"> <p>Panel 4 content</p> </div> </div> <button class="buttonPrev" id="pagination-prev"><< Prev</button> <button class="buttonNext" id="pagination-next">Next >></button> </section>

You have to add eventListener to your button elements

buttonNext.addEventListener("click", myFunction);
buttonPrev.addEventListener("click", myFunction);

function myFunction() {
  console.log("next")
}

Here are your Button Elements

<button id="nextBtn" class="buttonNext"><< Prev</button>
<button id="prevBtn" class="buttonPrev">Next >></button>

You have to get elements directly from DOM. use a unique class name or id for this purpose

const buttonNext = document.querySelector("#nextBtn");
const buttonPrev = document.querySelector("#prevBtn");

Now if the buttonNext and buttonPrev variables have the elements you can add eventListener. The event listener is of type click so whenever user clicks on any button the respective function will be called

buttonNext && buttonNext.addEventListener("click", handleNext);
buttonPrev && buttonPrev.addEventListener("click", handlePrev);


const handleNext = () => {
  console.log("next")
}

 const handlePrev = () => {
      console.log("next")
    }

I hope this will work for you. You can add any logic on next and prev buttons in respective functions

Working codepen demo

class Tabs {
  constructor() {
    this.tabsBlocks = document.querySelectorAll(".tabs-block");
  }

  init() {
    if (this.tabsBlocks.length > 0) {
      Array.prototype.forEach.call(this.tabsBlocks, (tabBlock, index) => {
        const tabContainer = tabBlock.querySelector(".tab-wrapper");
        const tabs = tabBlock.querySelectorAll("button");
        const panels = tabBlock.querySelectorAll(".panel");

        const Navigate= () => {
       const buttonNext = document.querySelector("#nextBtn");
        const buttonPrev = document.querySelector("#prevBtn");
        
        

    const handleNext = () => {
      console.log("next");
    };

    const handlePrev = () => {
      console.log("prev");
    };
          
          buttonNext && buttonNext.addEventListener("click", handleNext);
    buttonPrev && buttonPrev.addEventListener("click", handlePrev);
    }
        
        
       Navigate()

        tabContainer.setAttribute("role", "tablist");

        Array.prototype.forEach.call(tabs, (tab) => {
          if (tab.dataset.open === "true") this.toggleTabs(tab, panels);

          tab.setAttribute("role", "tab");
          tab.setAttribute(
            "aria-controls",
            `panel-${tab.dataset.target}-block-${index + 1}`
          );

          const associatedPanel = tabBlock.querySelector(
            `[data-panel="${tab.dataset.target}"]`
          );

          if (associatedPanel !== null) {
            associatedPanel.id = `panel-${tab.dataset.target}-block-${
              index + 1
            }`;
            tab.id = `tab-${tab.dataset.target}-block-${index + 1}`;
          }

          tab.addEventListener("click", () => {
            this.toggleTabs(tab, panels);
          });
        });

        Array.prototype.forEach.call(panels, (panel) => {
          const associatedTab = tabBlock.querySelector(
            `[data-target="${panel.dataset.panel}"]`
          );

          panel.setAttribute("role", "tabpanel");
          panel.setAttribute("aria-labelledby", `${associatedTab.id}`);
        });
      });
    }
  }

  toggleTabs = (currentTab, panels, buttonNext, buttonPrev) => {
    const tabs = currentTab.closest(".tabs-block").querySelectorAll("button");

    const target = currentTab.dataset.target;

    Array.prototype.forEach.call(tabs, (tab) => {
      if (tab.dataset.target !== target) {
        tab.classList.remove("is-active");
        tab.setAttribute("aria-selected", "false");
      }
    });

    Array.prototype.forEach.call(panels, (panel) => {
      if (panel.dataset.panel !== target) {
        panel.classList.remove("is-active");
      } else {
        panel.classList.add("is-active");
        currentTab.classList.add("is-active");
        currentTab.setAttribute("aria-selected", "true");
      }
    });
    
    

    
  };
}

const components = {
  Tabs: new Tabs()
};
components.Tabs.init();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM