41 lines
1.3 KiB
JavaScript
41 lines
1.3 KiB
JavaScript
export const scrollTo = ($el, offset = 0, offsetInPx = false) => {
|
||
return new Promise((resolve) => {
|
||
if (!$el) {
|
||
console.warn('Элемент не найден');
|
||
resolve();
|
||
return;
|
||
}
|
||
|
||
const elementPosition = $el.getBoundingClientRect().top + window.scrollY;
|
||
const topOffset = offsetInPx ? offset : (window.innerHeight * offset) / 100;
|
||
const targetScrollTop = elementPosition - topOffset;
|
||
|
||
// Если элемент уже в нужной позиции
|
||
if (Math.abs(window.scrollY - targetScrollTop) < 1) {
|
||
resolve();
|
||
return;
|
||
}
|
||
|
||
let resolved = false; // На случай, если scrollend и fallback запустятся одновременно
|
||
let fallbackTimeout; // eslint-disable-line prefer-const
|
||
|
||
const done = () => {
|
||
if (resolved) return;
|
||
resolved = true;
|
||
|
||
window.removeEventListener('scrollend', done);
|
||
clearTimeout(fallbackTimeout);
|
||
|
||
resolve();
|
||
};
|
||
|
||
window.addEventListener('scrollend', done, { once: true });
|
||
fallbackTimeout = setTimeout(done, 1500);
|
||
|
||
window.scrollTo({
|
||
top: targetScrollTop,
|
||
behavior: 'smooth',
|
||
});
|
||
});
|
||
};
|