Есть ли колбек для window.scrollTo?
Я хочу вызвать метод focus()
для элемента ввода после окончания прокрутки окна. Я использую плавное поведение для метода scrollTo()
. Проблема в том, что метод focus
нарушает плавное поведение. Решение заключается в том, чтобы вызвать функцию focus
сразу после завершения прокрутки.
Однако я не могу найти документацию или обсуждений, касающихся того, как определить конец метода scrollTo
.
let el = document.getElementById('input')
let elScrollOffset = el.getBoundingClientRect().top
let scrollOffset = window.pageYOffset || document.documentElement.scrollTop
let padding = 12
window.scrollTo({
top: elScrollOffset + scrollOffset - padding,
behavior: 'smooth'
})
// дождаться завершения прокрутки и затем
el.focus()
Есть ли у кого-нибудь идеи?
4 ответ(ов)
Ваше решение с использованием функции scrollTo
выглядит весьма элегантно и позволяет избежать перезаписи глобального события window.onscroll
. Основная идея заключается в том, чтобы отслеживать событие прокрутки и вызывать коллбэк только тогда, когда достигнуто нужное смещение.
Вот краткий анализ вашего кода:
Функция: Вы создали обобщенную функцию, которая принимает два параметра:
offset
— смещение, до которого нужно прокрутить страницу, иcallback
— коллбэк, вызываемый при достижении заданного положения прокрутки.Фиксированное смещение: Вы используете
toFixed()
, чтобы привести значениеoffset
к стандартному виду. Это хорошо, так как так вы избегаете ошибок связных с плавающей запятой.Обработчик прокрутки: Вы создаете функцию
onScroll
, которая проверяет, достигнуто ли необходимое смещение. В случае совпадения, вы удаляете обработчик события и вызываете переданный коллбэк.Добавление и выполнение: Вы добавляете обработчик события
scroll
и сразу вызываетеonScroll
, чтобы проверить, на каком этапе находитесь в момент выполнения.Прокрутка: В конце вы вызываете
window.scrollTo
с заданным смещением и поведением "плавно".
Таким образом, ваш код безопасен и не нарушает глобальное состояние. Это позволяет избежать конфликтов с другими возможными обработчиками события прокрутки на странице. Отличная работа!
Ваше решение действительно работает, но, возможно, оно немного "хакерское". Ваша логика прокрутки и установка фокуса при достижении целевой позиции достаточно изящны, однако есть несколько моментов, которые можно улучшить для более чистого и устойчивого кода.
Во-первых, вы используете событие onscroll
, чтобы отслеживать, когда страница достигла целевой позиции. Хотя это сработает, лучше использовать более предсказуемый подход, например, IntersectionObserver
, который позволяет выполнять действия, когда элемент становится видимым в пределах области просмотра. Это избавит вас от необходимости вручную управлять обработчиком событий прокрутки.
Вот возможный пример улучшенного кода:
let el = document.getElementById('input');
let padding = 12;
let targetPosition = el.getBoundingClientRect().top + window.pageYOffset - padding;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
// Используем IntersectionObserver для фокуса
let observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.focus();
observer.disconnect(); // отключаем наблюдение
}
});
});
// Начинаем наблюдение за элементом
observer.observe(el);
Этот код будет более эффективным и читаемым. Он использует IntersectionObserver
, чтобы точно определить, когда элемент попадает в область видимости, и устанавливает фокус на него без необходимости в ручной проверке прокрутки. Надеюсь, это поможет сделать ваш код более "чистым" и поддерживаемым!
Другие ответы мне не совсем подошли, поэтому, основываясь на ответе @Fabian von Ellerts, я написал собственное решение.
У меня были следующие проблемы:
- Элемент, который я прокручивал (и все его родительские элементы в иерархии), всегда имел
offsetTop
равный 0, поэтому это не сработало. - Мне нужно было прокрутить вложенный элемент.
Использование getBoundingClientRect
и элемента-контейнера в качестве ориентира работает:
const smoothScrollTo = (
scrollContainer,
scrolledContent,
offset,
callback
) => {
const fixedOffset = (
scrollContainer.getBoundingClientRect().top + offset
).toFixed();
const onScroll = () => {
if (
scrolledContent.getBoundingClientRect().top.toFixed() ===
fixedOffset
) {
scrollContainer.removeEventListener('scroll', onScroll);
callback();
}
};
scrollContainer.addEventListener('scroll', onScroll);
onScroll();
scrollContainer.scrollTo({
top: offset,
behavior: 'smooth',
});
}
Надеюсь, это поможет тем, кто сталкивается с аналогичными проблемами!
Вы можете сделать асинхронную версию функции scrollTo
, используя промисы и обработчики событий. В вашем коде вы заменили устаревший pageYOffset
на window.scrollY
, что является хорошим улучшением. Также вы добавили точки с запятой, что делает код более читаемым.
Вот ваш код с некоторыми небольшими комментариями для пояснения:
/**
* Асинхронная функция прокрутки
* @param offset - смещение, к которому нужно прокрутиться
*/
async function scrollTo(offset) {
return new Promise((resolve, reject) => {
const fixedOffset = offset.toFixed(); // Округляем значение смещения
const onScroll = function () {
// Проверяем, достигли ли нужного положения на странице
if (window.scrollY.toFixed() === fixedOffset) {
window.removeEventListener('scroll', onScroll); // Убираем обработчик события прокрутки
resolve(); // Разрешаем промис
}
};
window.addEventListener('scroll', onScroll); // Добавляем обработчик события прокрутки
onScroll(); // Вызываем функцию сразу, чтобы проверить текущее положение
window.scrollTo({
top: offset, // Прокручиваем страницу к заданному смещению
behavior: 'smooth' // Используем плавную прокрутку
});
});
}
Не забудьте, что использование асинхронных функций и промисов позволяет управлять потоками выполнения. Таким образом, вы можете вызывать scrollTo()
и использовать await
для ожидания завершения прокрутки перед выполнением других действий.
Как перенаправить на другую веб-страницу?
Где найти документацию по форматированию даты в JavaScript?
Как определить нажатие клавиши Esc?
Как проверить, содержит ли массив строку в TypeScript?
Ссылка и выполнение внешнего JavaScript-файла, размещенного на GitHub