68 lines
2.0 KiB
JavaScript
68 lines
2.0 KiB
JavaScript
// modules/sticky-fade/index.js
|
|
import { registerFrameTask, unregisterFrameTask } from '../../core/frameloop.js';
|
|
|
|
let taskId = 'sticky-fade';
|
|
let elements = [];
|
|
let lastScrollY = window.scrollY;
|
|
let activeMap = new WeakMap();
|
|
let configCache = {
|
|
direction: false,
|
|
reset: false,
|
|
};
|
|
|
|
|
|
export function init(config = {}) {
|
|
elements = Array.from(document.querySelectorAll('[data-sticky-fade]'));
|
|
if (elements.length === 0) return;
|
|
|
|
configCache.direction = config.direction ?? false;
|
|
configCache.reset = config.reset ?? false;
|
|
|
|
registerFrameTask(taskId, () => {
|
|
const scrollY = window.scrollY;
|
|
const direction = scrollY > lastScrollY ? 'down' : scrollY < lastScrollY ? 'up' : 'none';
|
|
lastScrollY = scrollY;
|
|
|
|
const viewportHeight = window.innerHeight;
|
|
|
|
elements.forEach(el => {
|
|
const rect = el.getBoundingClientRect();
|
|
const progress = 1 - Math.min(Math.max(rect.top / viewportHeight, 0), 1);
|
|
|
|
el.style.opacity = progress.toFixed(3);
|
|
el.style.transform = `translateY(${(1 - progress) * 20}px)`;
|
|
|
|
if(configCache.direction) {
|
|
el.dataset.scrollDir = direction;
|
|
}
|
|
|
|
if (configCache.reset) {
|
|
const isVisible = progress >= 1;
|
|
const wasActive = activeMap.get(el) || false;
|
|
|
|
if(isVisible && !wasActive) {
|
|
el.classList.add('visible');
|
|
activeMap.set(el, true);
|
|
} else if(!isVisible && wasActive) {
|
|
el.classList.remove('visible');
|
|
activeMap.set(el, false);
|
|
}
|
|
}
|
|
});
|
|
}, { autoStart: true });
|
|
}
|
|
|
|
export function destroy() {
|
|
unregisterFrameTask(taskId);
|
|
|
|
elements.forEach(el => {
|
|
el.style.opacity = '';
|
|
el.style.transform = '';
|
|
el.classList.remove('visible');
|
|
delete el.dataset.scrollDir;
|
|
});
|
|
|
|
elements = [];
|
|
activeMap = new WeakMap();
|
|
}
|