Как по клику на элемент (динамически) определить - нужен ли элемент по середине экрана либо его невозможно отобразить целиком и скроллить страницу нужно до фрагмента, когда его можно начать читать (в топ видимой области).
Factory pattern in action
const scrollToIdCreator = ({ timeout, offsetTop, elementHeightLimit }: {
timeout: number;
offsetTop: number;
elementHeightLimit: number;
}) => {
let _timeout: NodeJS.Timeout | undefined = undefined
return ({ id }: { id: string }) => {
try {
const nodeId = id
const targetElm = document.getElementById(nodeId)
if (!!targetElm) {
if (!!_timeout) clearTimeout(_timeout)
_timeout = setTimeout(() => {
const curHeight = targetElm.getBoundingClientRect().height
if (curHeight <= elementHeightLimit) {
// NOTE: Скроллить до середины контента
targetElm?.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest',
})
} else {
// NOTE: Скроллить в начало контента
const elementPosition = targetElm.getBoundingClientRect().top
const offsetPosition = elementPosition + window.pageYOffset - offsetTop
window.scrollTo({
top: offsetPosition,
behavior: 'smooth',
});
}
}, timeout)
}
else
console.log(`⚠️ Node not found nodeId=${id}`)
} catch (err) {
console.warn(err)
}
}
}
Usage (abstractions principle in action)
// STEP 1: Создаем обработчик с настройками
const scrollToId = scrollToIdCreator({
// NOTE: Таймаут (и он же будет работать как дебаунс)
timeout: 200,
// NOTE: Настройка поведения скролла в зависимости от
// высоты элемента: Если элемент меньше (или равен) лимиту высоты,
// то скролл будет произведен так, чтоб элемент оказался
// посередине высоты Viewport (область которую видит пользователь
// на экране), иначе ориентиром будет верхняя граница Viewport
elementHeightLimit: 300,
// NOTE: Отступ от верхней границы (если элемент слишком большой
// и не помещается в те рамки, которые мы указали
// в параметре elementHeightLimit выше)
offsetTop: 16,
})
// STEP 2: Вызываем обработчик, передаем id элемента
scrollToId({ id: 'element_id' })
Если нужна более гибкая настройка поведения скролла - можем легко дописать этот код: К примеру, вместо настройки elementHeightLimit
мы можем передать коллбэк, который получит все интересующие параметры текущего элемента и функции для вызова двух вариантов скролла - которые могут быть вызваны в зависимости от проверок внутри коллбэка.