vanillajs-scrollspy
Version:
ScrollSpy in pure JavaScript
88 lines (69 loc) • 2.16 kB
JavaScript
class VanillaScrollspy {
constructor({ menu, speed = 2000, easing = 'easeOutSine' }) {
this.$menu = menu;
this.speed = speed;
this.easing = easing;
}
scrollToY(targetY = 0) {
let currentTime = 0;
const scrollTargetY = targetY;
const scrollY = window.scrollY || document.documentElement.scrollTop;
const time = Math.max(
0.1,
Math.min(Math.abs(scrollY - scrollTargetY) / this.speed, 0.8)
);
const easingEquations = {
easeOutSine(pos) {
return Math.sin(pos * (Math.PI / 2))
},
easeInOutSine(pos) {
return -0.5 * (Math.cos(Math.PI * pos) - 1)
},
easeInOutQuint(pos) {
if ((pos /= 0.5) < 1) return 0.5 * pos ** 5
return 0.5 * ((pos - 2) ** 5 + 2)
}
};
const tick = () => {
currentTime += 1 / 60;
const p = currentTime / time;
const t = easingEquations[this.easing](p);
if (p < 1) {
window.requestAnimationFrame(tick);
window.scrollTo(0, scrollY + (scrollTargetY - scrollY) * t);
return
}
window.scrollTo(0, scrollTargetY);
};
tick();
}
menuControl() {
const $links = this.$menu.querySelectorAll('a[href^="#"]');
const scrollPos = window.scrollY || document.documentElement.scrollTop;
$links.forEach((link) => {
const $elem = document.querySelector(link.getAttribute('href'));
return $elem.offsetTop <= scrollPos &&
$elem.offsetTop + $elem.clientHeight > scrollPos
? link.classList.add('active')
: link.classList.remove('active')
});
}
animated() {
const $links = this.$menu.querySelectorAll('a[href^="#"]');
const self = this;
function control(e) {
e.preventDefault();
const $target = document.querySelector(this.hash);
self.scrollToY($target.offsetTop);
}
$links.forEach((link) => link.addEventListener('click', control));
}
init() {
this.animated();
document.addEventListener('scroll', () => this.menuControl());
}
}
function vanillaScrollspy(...args) {
return new VanillaScrollspy(...args)
}
export { vanillaScrollspy as default };