UNPKG

micro-scrollspy

Version:

A lightweight library for implementing scrollspy functionality in web applications.

91 lines (75 loc) 2.9 kB
// Import dependencies import scrollama from 'scrollama'; // For scroll events import throttle from 'lodash.throttle'; // To throttle scroll events import delegate from 'delegate'; // For easy event delegation // Polyfills import 'intersection-observer'; // Polyfill for intersection observer import smoothscroll from 'smoothscroll-polyfill'; // Polyfill for smooth scrolling // Initialize polyfills smoothscroll.polyfill(); class LightweightScrollSpy { /** * Initializes the scrollspy with options * @param {Object} options - Configuration options for the scrollspy */ constructor(options) { // Default options this.defaultOptions = { sections: 'section', // Selector for the sections navLinks: 'nav a', // Selector for the navigation links activeClass: 'active', // Class to be added to the active link offset: 0.5, // Intersection observer offset (viewport ratio) }; // Extend default options with user-provided options this.options = { ...this.defaultOptions, ...options }; // Initialize scrollama this.scroller = scrollama(); this.init(); } /** * Sets up the scrollama instance and event listeners */ init() { // Scrollama setup this.scroller.setup({ step: this.options.sections, // Elements to observe offset: this.options.offset, // Trigger offset }) .onStepEnter(this.handleStepEnter.bind(this)) .onStepExit(this.handleStepExit.bind(this)); // Throttle scroll event to improve performance window.addEventListener('scroll', throttle(this.handleScroll.bind(this), 200)); // Delegate click event for navigation links to enable smooth scroll delegate(this.options.navLinks, 'click', this.handleNavLinkClick.bind(this)); } /** * Handles entering a section * @param {Object} response - The response object from scrollama */ handleStepEnter(response) { // Remove active class from all links document.querySelectorAll(this.options.navLinks).forEach(link => { link.classList.remove(this.options.activeClass); }); // Find the navigation link corresponding to the section const activeLink = document.querySelector(`[href="#${response.element.id}"]`); // Add active class to the corresponding link if (activeLink) { activeLink.classList.add(this.options.activeClass); } } /** * Handles navigation link clicks to smoothly scroll to the section * @param {Event} event - The click event */ handleNavLinkClick(event) { event.preventDefault(); const targetId = event.delegateTarget.getAttribute('href').substring(1); const targetSection = document.getElementById(targetId); // Use the smooth scroll polyfill to scroll to the section if (targetSection) { targetSection.scrollIntoView({ behavior: 'smooth' }); } } } export default LightweightScrollSpy;