idiotWu / smooth-scrollbar

Customizable, Extendable, and High-Performance JavaScript-Based Scrollbar Solution.

Home Page:https://idiotwu.github.io/smooth-scrollbar/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Touch events on splide slider broke smooth scroll

tdaulbaev opened this issue · comments

Environment

  • Browser: Ubuntu Desktop Chrome 97, Android mobile chrome 97
  • Version of smooth-scrollbar: 8.7.3
  • Slider: https://splidejs.com (@splidejs/react-splide) ver. 0.6.17

Current Behavior

While scrolling the page, if the touch event hits at horizontal slider with drag = true, smooth scrolling breaks.
The smooth transition disappears and a small movement of the fingers can cause an instant jump (delta Y) of 1000+ pixels.

Expected Behavior

When smooth scroll hitting dragable elements should not break smooth scrolling.

Steps to Reproduce

<smooth-scrollbar>
     <SplideSlider />
<smooth-scrollbar>

I had the same problem with the swiper slider too.

Thanks for providing the details! Libraries like the one you are using have to call touchMoveEvent.preventDefault() to perform customized touch scrolling action. However, as per the current design, we ignore any default-prevented events and therefore the touch moving speed will not be tracked. Can you try commenting out the return statement in the following code to see if it works in your environment?

function handler(event: any) {
// ignore default prevented events
if (event.defaultPrevented) {
return;
}
fn(event);
}

After a little debugging I found they even call evt.preventDefault() in touch-end events, and this prevents touch trackers from being released. IMHO it's totally unnecessary to do so 🤔

Fixed in v8.7.4.

I also created a related discussion in splide: Splidejs/splide#625

As we still ignore the default-prevented touchend event, you may need to manually save&restore option.damping, otherwise it will be locked to 0.5:

let damping = 0;
let pointerCount = 0;

container.addEventListener('touchstart', (e) => {
  // save damping
  if (pointerCount === 0) {
     damping = scrollbar.options.damping;
  }

  pointerCount++;
  // more accurate?
  // pointerCount += e.changedTouches.length
});

container.addEventListener('touchend', () => {
  pointerCount--;
  // more accurate?
  // pointerCount -= e.changedTouches.length

  // restore damping
  if (pointerCount === 0) {
    scrollbar.options.damping = damping;
  }
});

See also:

addEvent(target, 'touchstart', (evt: TouchEvent) => {
// start records
touchRecord.track(evt);
// stop scrolling
scrollbar.setMomentum(0, 0);
// save damping
if (pointerCount === 0) {
damping = scrollbar.options.damping;
scrollbar.options.damping = Math.max(damping, 0.5); // less frames on touchmove
}
pointerCount++;
});

addEvent(target, 'touchcancel touchend', (evt: TouchEvent) => {
const delta = touchRecord.getEasingDistance(damping);
scrollbar.addTransformableMomentum(
delta.x,
delta.y,
evt,
);
pointerCount--;
// restore damping
if (pointerCount === 0) {
scrollbar.options.damping = damping;
}
touchRecord.release(evt);
activeScrollbar = null;
});

in my case, after i update to 8.7.4 and manually restoring damping didn't change anything. still had broken behavior.

@tdaulbaev have you tried saving&restoring options.damping as I commented above?

Yes!
I guess I'll just turn off smooth scrolling on mobile devices, bacouse mobile browsers provide similar scroll behavior by default

Yeah, I totally agree. I'm not too fond of using it on mobile devices either 😆

Thanks!

there was an error in my implementation, now everything works!