Files
gemini-banlancer/frontend/js/components/slidingTabs.js
2025-11-20 12:24:05 +08:00

81 lines
2.8 KiB
JavaScript

export default class SlidingTabs {
/**
* @param {HTMLElement} containerElement - The main container element with the `data-sliding-tabs-container` attribute.
*/
constructor(containerElement) {
this.container = containerElement;
this.indicator = this.container.querySelector('[data-tab-indicator]');
this.tabs = this.container.querySelectorAll('[data-tab-item]');
// Find the initially active tab and store it as the component's state
this.activeTab = this.container.querySelector('.tab-active');
if (!this.indicator || this.tabs.length === 0) {
console.error('SlidingTabs component is missing required elements (indicator or items).', this.container);
return;
}
this.init();
}
init() {
// Set initial indicator position
if (this.activeTab) {
// Use a small delay to ensure layout is fully calculated
setTimeout(() => this.updateIndicator(this.activeTab), 50);
}
// Bind all necessary event listeners
this.bindEvents();
}
updateIndicator(targetTab) {
if (!targetTab) return;
const containerRect = this.container.getBoundingClientRect();
const targetRect = targetTab.getBoundingClientRect();
const left = targetRect.left - containerRect.left;
const width = targetRect.width;
this.indicator.style.left = `${left}px`;
this.indicator.style.width = `${width}px`;
}
bindEvents() {
this.tabs.forEach(tab => {
// On click, update the active state
tab.addEventListener('click', (e) => {
// e.preventDefault(); // Uncomment if using <a> tags for SPA routing
if (this.activeTab) {
this.activeTab.classList.remove('tab-active');
}
tab.classList.add('tab-active');
this.activeTab = tab; // Update the component's state
this.updateIndicator(this.activeTab);
});
// On hover, preview the indicator position
tab.addEventListener('mouseenter', () => {
this.updateIndicator(tab);
});
});
// When the mouse leaves the entire container, reset indicator to the active tab
this.container.addEventListener('mouseleave', () => {
this.updateIndicator(this.activeTab);
});
}
}
// ---- Auto-Initialization Logic ----
// This is the "bootstrapper". It finds all components on the page and brings them to life.
document.addEventListener('DOMContentLoaded', () => {
const allTabContainers = document.querySelectorAll('[data-sliding-tabs-container]');
allTabContainers.forEach(container => {
new SlidingTabs(container);
});
});