-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disable window scrolling while swiping horizontally [MOBILE] #1240
Comments
yep. I'm having a same issue :( |
Is there any updates on this? |
Having the same issue. If I had to guess, this is related to the fact that calling I'll update if I figure it out. Would love an update if anyone has found a good workaround. |
Here is my solution, it works fine for me
|
You can read more about passive events here -> LINK |
@ninosaurus |
How about this? componentDidMount(){
window.addEventListener('touchstart', this.touchStart);
window.addEventListener('touchmove', this.preventTouch, {passive: false});
}
componentWillUnmount(){
window.removeEventListener('touchstart', this.touchStart);
window.removeEventListener('touchmove', this.preventTouch, {passive: false});
}
touchStart(e){
this.firstClientX = e.touches[0].clientX;
this.firstClientY = e.touches[0].clientY;
}
preventTouch(e){
const minValue = 5; // threshold
this.clientX = e.touches[0].clientX - this.firstClientX;
this.clientY = e.touches[0].clientY - this.firstClientY;
// Vertical scrolling does not work when you start swiping horizontally.
if(Math.abs(this.clientX) > minValue){
e.preventDefault();
e.returnValue = false;
return false;
}
} |
Code above from @yunyong seems to work fine. Thanks |
Hello, I used your plug-in on the mobile side, but in the page to add "overflow:auto" to add the scroll bar, scroll bar content can not up and down, how to do? |
UP! It works for me, thank you! @yunyong |
Sorry for the stupid question, but where would this solution go? I use gatsbyjs and call the slider like this: https://pastebin.com/ZSY2gsEv |
I've tried calling |
It appears to be applied to a container component. It's watching the touch delta on the window itself and disabling the default window response to mouse movement (i.e. scrolling the body) if the x position of the mouse is a certain distance from the start position. This does mean however you can re-enable scrolling if the touch returns to the initial position. The fix for this would be to accumulate delta or flip a toggle once you're blocking scrolling that you toggle back on touch release. |
@yunyong We've got your solution working, however it seems like it sometimes interferes with the vertical scrolling of the page on mobile? What we have, seems to be rather unreliable and I'm wondering if it's how we implemented it vs the solution itself? this is the code we have in our stateless functional component... const [firstClientX, setFirstClientX] = useState();
const [firstClientY, setFirstClientY] = useState();
const [clientX, setClientX] = useState();
useEffect(() => {
const touchStart = e => {
setFirstClientX(e.touches[0].clientX);
setFirstClientY(e.touches[0].clientY);
};
const preventTouch = e => {
const minValue = 5; // threshold
setClientX(e.touches[0].clientX - firstClientX);
// Vertical scrolling does not work when you start swiping horizontally.
if (Math.abs(clientX) > minValue) {
e.preventDefault();
e.returnValue = false;
return false;
}
};
window.addEventListener('touchstart', touchStart);
window.addEventListener('touchmove', preventTouch, { passive: false });
return () => {
window.removeEventListener('touchstart', touchStart);
window.removeEventListener('touchmove', preventTouch, {
passive: false,
});
};
}, [clientX, firstClientX, firstClientY]); |
following the code by @yunyong I've come up with a solution that doesn't break the window horizontal scroll by adding the Also @iDVB I don't think it's a good idea to save the let firstClientX, clientX;
const preventTouch = e => {
const minValue = 5; // threshold
clientX = e.touches[0].clientX - firstClientX;
// Vertical scrolling does not work when you start swiping horizontally.
if (Math.abs(clientX) > minValue) {
e.preventDefault();
e.returnValue = false;
return false;
}
};
const touchStart = e => {
firstClientX = e.touches[0].clientX;
};
const Slider = ({ children, ...props }) => {
let containerRef = createRef();
useEffect(() => {
if (containerRef.current) {
containerRef.current.addEventListener("touchstart", touchStart);
containerRef.current.addEventListener("touchmove", preventTouch, {
passive: false
});
}
return () => {
if (containerRef.current) {
containerRef.current.removeEventListener("touchstart", touchStart);
containerRef.current.removeEventListener("touchmove", preventTouch, {
passive: false
});
}
};
});
return (
<div ref={containerRef}>
<ReactSlick {...settings} {...props}>
{children}
</ReactSlick>
</div>
);
}; |
Following up on the wonderful solutions from @yunyong , @iDVB , and @xavitb3 - I found that our implementation impacted UX in a negative way. Specifically, if a users
Why is the second consequence not desirable? Well, users reported the following experience to us:
Upon inspecting the Initially, it may seem like you can't expect consequence 1 without also expecting consequence 2, but my testing has led me to believe otherwise. Simply removing I hope this is helpful for others that bump into this issue, but please raise a red flag if you see any issues with my logic. |
Also stumbled upon this issue. Any estimation if we could get a solution right in the library? |
I solved this problem like so:
No htmlRefs and no re- and deregistering of eventListeners needed. |
How can you call |
yeah.. still hacking this, here's my solution import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
// Some component definition
const slider = useRef(null);
const lockVerticalScrollWhenHorizontalSwiping = (direction: 'vertical' | 'right' | 'left'): void => {
const isHorizontal = direction !== 'vertical';
if (isHorizontal) {
// Will be released when the gesture finish even if the slide has no changed.
disableBodyScroll(slider.current);
}
};
const releaseBodyScroll = (): void => enableBodyScroll(slider.current);
return (
<div onTouchEnd={releaseBodyScroll}>
<Slider
ref={slider}
swipeEvent={lockVerticalScrollWhenHorizontalSwiping}
enableVerticalScroll
{...settings}
>
{theslides}
</Slider>
</div>
); |
Here's @xavi-tristancho's answer as a React Hook: import { RefObject, useCallback, useEffect, useRef } from 'react'
// @see https://github.com/akiran/react-slick/issues/1240#issuecomment-513235261
export function usePreventVerticalScroll<T extends HTMLElement>(ref: RefObject<T>, dragThreshold = 5) {
const firstClientX = useRef<number>(0)
const clientX = useRef<number>(0)
const preventTouch = useCallback(
(e: TouchEvent) => {
clientX.current = e.touches[0].clientX - firstClientX.current
// Vertical scrolling does not work when you start swiping horizontally.
if (Math.abs(clientX.current) > dragThreshold) {
e.preventDefault()
e.returnValue = false
return false
}
return true
},
[dragThreshold],
)
const touchStart = useCallback((e: TouchEvent) => {
firstClientX.current = e.touches[0].clientX
}, [])
useEffect(() => {
const current = ref.current
if (current) {
current.addEventListener('touchstart', touchStart)
current.addEventListener('touchmove', preventTouch, { passive: false })
}
return () => {
if (current) {
current.removeEventListener('touchstart', touchStart)
// Had to change this line to prevent a typing error. You may not have the issue:
// current.removeEventListener('touchmove', preventTouch, { passive: false })
current.removeEventListener('touchmove', preventTouch)
}
}
}, [preventTouch, ref, touchStart])
} |
When you start scrolling on mobile(Safari && Chrome from iOS) it is able to scroll vertically and thats bad UX. Is there any workarounds for that case.
My settings:
let settings = { className: this.props.className || '', infinite: true, lazyLoad: true, speed: 200, arrows: this.props.arrows, swipeToSlide: true, touchMove: true, nextArrow: <NextArrow/>, prevArrow: <PrevArrow/>, afterChange: this.props.afterChange, beforeChange: this.props.beforeChange, };
The text was updated successfully, but these errors were encountered: