使用垂直鼠标滚轮在 React 组件上水平滚动

Ben*_*gan 8 javascript scroll mousewheel horizontal-scrolling reactjs

我有一个组件,当在较小的桌面窗口中时,它会调整大小为一排水平的引导卡。对于没有水平鼠标滚轮且不使用触摸板的用户,我希望允许用户在悬停在此特定组件上时使用垂直鼠标滚轮移动水平滚动。

这是我基于我的代码的原始 StackOverflow 问题:https : //stackoverflow.com/a/15343916/8387497

水平滚动辅助组件:

function horizontalScroll (event) {
  const delta = Math.max(-1, Math.min(1, (event.nativeEvent.wheelDelta || -event.nativeEvent.detail)))
  event.currentTarget.scrollLeft -= (delta * 10)
  event.preventDefault
}
Run Code Online (Sandbox Code Playgroud)

我如何在需要水平滚动的组件上实现它:

<Row className='announcements-home' onWheel={horizontalScroll} >
Run Code Online (Sandbox Code Playgroud)

当我将此horizontalScroll辅助函数放置在 React onWheel 事件中时,它会水平和垂直滚动。我想要的结果只是水平滚动。此外,Firefox 似乎完全没有响应这些更改的水平滚动。

小智 8

onWheel = (e) => {
    e.preventDefault()
    var container = document.getElementById('container')
    var containerScrollPosition = document.getElementById('container').scrollLeft
    container.scrollTo({
        top: 0,
        left: largeContainerScrollPosition + e.deltaY
        behaviour: 'smooth' //if you want smooth scrolling
    })
}
Run Code Online (Sandbox Code Playgroud)


小智 8

TarVK 提出的钩子还有另一个小问题。一旦滚动到末尾并继续滚动,当我们习惯于包含也开始滚动的元素时,什么也不会发生。所以我对此进行了修复:

export function useHorizontalScroll () {
  const elRef = useRef();
  useEffect(() => {
    const el = elRef.current;
    if (el) {
      const onWheel = (e) => {
        if (e.deltaY === 0) return;
        if (
          !(el.scrollLeft === 0 && e.deltaY < 0) &&
          !(el.scrollWidth - el.clientWidth - Math.round(el.scrollLeft) === 0 && 
              e.deltaY > 0)
        ) {
          e.preventDefault();
        }
        el.scrollTo({
          left: el.scrollLeft + e.deltaY,
          behavior: 'smooth'
        });
      };
      el.addEventListener('wheel', onWheel);
      return () => el.removeEventListener('wheel', onWheel);
    }
  }, []);
  return elRef;
}
Run Code Online (Sandbox Code Playgroud)

仅当有空间可以朝该方向滚动时,它才会有条件地阻止默认行为,因此当没有空间可以滚动时,例如整个页面将开始滚动。变化在这里:

        if (
          !(el.scrollLeft === 0 && e.deltaY < 0) &&
          !(el.scrollWidth - el.clientWidth - Math.round(el.scrollLeft) === 0 && 
              e.deltaY > 0)
        ) {
          e.preventDefault();
        }
Run Code Online (Sandbox Code Playgroud)


Tar*_*rVK 7

好的,所以问题似乎是您只引用该函数event.preventDefault而不是调用它。在最后添加一些括号调用它应该做的伎俩: event.preventDefault()

然而,我在寻找一些简单的代码时发现了这个问题,所以如果其他人处于相同的情况,我也会保留我为此创建的钩子:

import { useRef, useEffect } from "react";

export function useHorizontalScroll() {
  const elRef = useRef();
  useEffect(() => {
    const el = elRef.current;
    if (el) {
      const onWheel = e => {
        if (e.deltaY == 0) return;
        e.preventDefault();
        el.scrollTo({
          left: el.scrollLeft + e.deltaY,
          behavior: "smooth"
        });
      };
      el.addEventListener("wheel", onWheel);
      return () => el.removeEventListener("wheel", onWheel);
    }
  }, []);
  return elRef;
}
Run Code Online (Sandbox Code Playgroud)

用法:

import React from "react";
import { useSideScroll } from "./useSideScroll";

export const SideScrollTest = () => {
  const scrollRef = useHorizontalScroll();
  return (
    <div ref={scrollRef} style={{ width: 300, overflow: "auto" }}>
      <div style={{ whiteSpace: "nowrap" }}>
        I will definitely overflow due to the small width of my parent container
      </div>
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

注意:在尝试进行连续滚动时,滚动行为“平滑”似乎会带来一些麻烦。可以省略此行为以获得适当的连续滚动,但它看起来会生涩。

据我所知,对此没有简单的解决方案。然而,我在我自己的项目中创建了一个相当复杂的解决方案,所以我想有些人可能也会欣赏:https : //gist.github.com/TarVK/4cc89772e606e57f268d479605d7aded