Я работаю над слайдером и хочу отключить вертикальную прокрутку страницы, когда пользователь выполняет горизонтальный жест по слайдеру.
Моей первоначальной идеей было проверить, палец переместился более чем на 50 пикселей по оси X и, если это так, заблокируйте вертикальную прокрутку. Я пытался использовать метод предотвращения Default(), чтобы предотвратить поведение прокрутки, но постоянно сталкивался с проблемами и неожиданным поведением.
Вот что я пробовал:
Записано событие touchstart для записи начальной позиции касания.
Слушал touchmove, чтобы отслеживать, насколько касание перемещалось по осям X и Y.
Если горизонтальное перемещение (ось X) превышало 50 пикселей, я вызывал событие .preventDefault() для блокировки вертикальная прокрутка.
Однако этот подход оказался ненадежным: иногда прокрутка не блокировалась должным образом, а иногда блокировалась, когда этого не должно было быть.
Ограничение:
Использование переполнения: скрыто для отключения прокрутки недопустимо, поскольку оно вызывает другие проблемы в моем пользовательском интерфейсе.
Вопрос:
Что такое лучший способ надежно отключить вертикальную прокрутку во время горизонтальной жесты смахивания? Есть ли лучший способ справиться с этим с помощью JavaScript?
const videoCardsEls = [...document.querySelectorAll('.video_card')];
const sliderRobotWrapperEls = [...document.querySelectorAll('.slider_robot_wrapper')];
const sliderShoppingWrapperEls = [...document.querySelectorAll('.slider_shopping_wrapper')];
const buttonPrevEls = [...document.querySelectorAll('.button_prev')];
const buttonNextEls = [...document.querySelectorAll('.button_next')];
const sliderTrackEls = [...document.querySelectorAll('.slider_track')];
const paginationCirclesEls = [...document.querySelectorAll('.pagination_circles')];
const configureSlider = ({
slidesEls,
paginationCirclesContainerEl,
sliderTrackEl,
buttonNextEl,
buttonPrevEl,
visibleSlidesCount
}) => {
const currentSlideIndex = {value: visibleSlidesCount};
let isAnimating = false;
let startX = 0;
let currentX = 0;
let isDragging = false;
const swipeThreshold = 50;
const minScreenWidthForSwipe = 1024;
const startDrag = e => {
if (isAnimating) return;
isAnimating = true;
const isVideoSlider = sliderTrackEl === sliderTrackEls[0];
if (isVideoSlider && window.innerWidth >= minScreenWidthForSwipe) return;
isDragging = true;
startX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
currentX = startX;
sliderTrackEl.style.transition = 'none';
};
const moveDrag = e => {
if (!isDragging) return;
currentX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
const diff = currentX - startX;
const offset = currentSlideIndex.value * slideWidth;
sliderTrackEl.style.transform = `translateX(${-offset + diff}px)`;
};
const endDrag = () => {
if (!isDragging) return;
isDragging = false;
const diff = currentX - startX;
sliderTrackEl.style.transition = 'transform 0.5s';
if (Math.abs(diff) > swipeThreshold) {
if (diff < 0) {
nextSlide({
currentSlideIndex,
sliderTrackEl,
slideWidth,
slidesEls,
paginationCirclesContainerEl,
visibleSlidesCount
});
} else {
prevSlide({
currentSlideIndex,
sliderTrackEl,
slideWidth,
slidesEls,
paginationCirclesContainerEl,
visibleSlidesCount
});
}
} else {
updateSliderPosition({
withTransition: true,
currentSlideIndex,
sliderTrackEl,
slideWidth
});
}
setTimeout(() => {
isAnimating = false;
}, 500);
};
const addDragEvents = sliderTrackEl => {
sliderTrackEl.addEventListener('touchstart', startDrag, {passive: true});
sliderTrackEl.addEventListener('touchmove', moveDrag, {passive: true});
sliderTrackEl.addEventListener('touchend', endDrag);
sliderTrackEl.addEventListener('mousedown', startDrag);
sliderTrackEl.addEventListener('mousemove', moveDrag);
sliderTrackEl.addEventListener('mouseup', endDrag);
sliderTrackEl.addEventListener('mouseleave', endDrag);
};
addDragEvents(sliderTrackEl);
};
configureSlider({
slidesEls: videoCardsEls,
paginationCirclesContainerEl: paginationCirclesEls[0],
sliderTrackEl: sliderTrackEls[0],
visibleSlidesCount: 2,
});
configureSlider({
slidesEls: sliderRobotWrapperEls,
paginationCirclesContainerEl: paginationCirclesEls[1],
sliderTrackEl: sliderTrackEls[1],
buttonNextEl: buttonNextEls[0],
buttonPrevEl: buttonPrevEls[0],
visibleSlidesCount: 3,
});
configureSlider({
slidesEls: sliderShoppingWrapperEls,
paginationCirclesContainerEl: paginationCirclesEls[2],
sliderTrackEl: sliderTrackEls[2],
buttonNextEl: buttonNextEls[1],
buttonPrevEl: buttonPrevEls[1],
visibleSlidesCount: 4,
});
Подробнее здесь: https://stackoverflow.com/questions/793 ... n-a-slider