[英]Tabs how can I add next and prev buttons?
选项卡如何添加下一个和上一个按钮?
我有一个选项卡组件,需要下一个和上一个按钮作为要求。
我尝试构建组件,现在需要额外的一点,但我有点卡住了。
我不确定如何调用 function 并使其在现有电话中工作。
如何为下一个和上一个按钮添加额外的点击 function?
让它工作真的很有用。 如果有人能够让我走上正确的道路,也许即使在正确的位置使用一些 console.log 也可以使用单击?
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>
这个例子在 codepen 上有效,但在这里不适用。也许babel
preprozessor 做了一些我不知道的事情......
将其复制到 codepen,您会很高兴。
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>
您必须将 eventListener 添加到按钮元素
buttonNext.addEventListener("click", myFunction);
buttonPrev.addEventListener("click", myFunction);
function myFunction() {
console.log("next")
}
这是您的按钮元素
<button id="nextBtn" class="buttonNext"><< Prev</button>
<button id="prevBtn" class="buttonPrev">Next >></button>
您必须直接从 DOM 获取元素。 为此使用唯一的 class 名称或 ID
const buttonNext = document.querySelector("#nextBtn");
const buttonPrev = document.querySelector("#prevBtn");
现在,如果 buttonNext 和 buttonPrev 变量具有您可以添加 eventListener 的元素。 事件侦听器是单击类型,因此每当用户单击任何按钮时,将调用相应的 function
buttonNext && buttonNext.addEventListener("click", handleNext);
buttonPrev && buttonPrev.addEventListener("click", handlePrev);
const handleNext = () => {
console.log("next")
}
const handlePrev = () => {
console.log("next")
}
我希望这对你有用。 您可以在各自功能的下一个和上一个按钮上添加任何逻辑
工作代码笔演示
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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.