简体   繁体   中英

How to detect scroll direction when content changes height on scroll

It's quite straightforward to detect the scroll direction when scrolling page with static size. But if one of the elements is a sticky header and changes the height while scrolling it keeps changes pageYOffset and enters into infinite loop jumping up and down.

Example sandbox where if you scroll to the point were it starts shrinking it starts jumping.

Some possible solution I've came up with was to add a spacer which would compensate when the sticky navigation gets smaller. But that requires doing it in the actual component. Wondering if there is a way to do it with js only in the useScrollDirection hook.

One of the other things I've tried was to use document.documentElement.scrollHeight and check for the size change, that didn't help as well.

Just a suggestion. I think you are underutilizing position: sticky . You don't need an event listener to achieve the behavior you want. You can do this entirely with CSS and let the browser handle everything for you.

 .app { font-family: sans-serif; text-align: center; height: 300vh; }.nav { position: sticky; top: -120px; height: 150px; background: aquamarine }.nav_item { position: sticky; top: 0px; margin: 0; }
 <div class="app"> <h1>Hello CodeSandbox</h1> <nav class="nav"> <p class="nav_item">Hello</p> </nav> <h2>Start editing to see some magic happen!</h2> </div>

I encountered the same problem and a co-worker recommended me to listen to the wheel event. So I implemented the following react hook:

const useLastMouseWheelDirection = () => {
  const [lastMouseWheelDirection, setLastMouseWheelDirection] = useState(
    undefined
  )

  useEffect(() => {
    const handler = (event) => {
      setLastMouseWheelDirection(event.deltaY >= 0 ? 'down' : 'up')
    }
    window.addEventListener('wheel', handler)
    return () => window.removeEventListener('wheel', handler)
  }, [])

  return lastMouseWheelDirection
}

This solution has some serious limitations:

  • Obviously touch events are ignored
  • Clicking and dragging the scroll bar will not fire the event

Also a side effect to the desired behavior would be that it wouldn't take into consideration if the element is even overflowing or not, although the hook could be extended to catch this case.

Further more the MDN Web Docs state:

Note: Don't confuse the wheel event with the scroll event. The default action of a wheel event is implementation-specific, and doesn't necessarily dispatch a scroll event. Even when it does, the delta* values in the wheel event don't necessarily reflect the content's scrolling direction. Therefore, do not rely on the wheel event's delta* properties to get the scrolling direction. Instead, detect value changes of scrollLeft and scrollTop of the target in the scroll event.

So please take this answer with a grain of salt.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM