react wheelpicker问题求助

188 阅读1分钟

react框架 typescript语言 自定义了一个wheelpicker组件,但是滚轮滚动一下会划过三个选项,没办法准确的选择其中一个,想问问大家有没有什么办法可以解决这个问题

import React, { useRef, useEffect } from 'react';
import { Box, List, ListItem } from '@mui/material';

interface WheelPickerProps {
  range: number[];
  onSelect: (value: number) => void;
}

const WheelPicker: React.FC<WheelPickerProps> = ({ range, onSelect }) => {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const container = containerRef.current;

    if (container) {
      const handleScroll = () => {
        const scrollPosition = container.scrollTop + container.clientHeight / 2;
        const itemHeight = container.children[0].clientHeight;
        const selectedIndex = Math.round(scrollPosition / itemHeight) - 1; // 减去上方占位元素的高度
        if (selectedIndex >= 0 && selectedIndex < range.length) {
          const selectedValue = range[selectedIndex];
          onSelect(selectedValue);
        }
      };

      container.addEventListener('scroll', handleScroll);

      return () => {
        container.removeEventListener('scroll', handleScroll);
      };
    }
  }, [range, onSelect]);

  return (
    <Box
      sx={{
        position: 'relative',
        height: '200px',
        width: '100px',
        backgroundColor: '#333', // 设置背景颜色
      }}
    >
      <Box
        ref={containerRef}
        sx={{
          height: '100%',
          overflowY: 'auto',
          scrollBehavior: 'smooth',
          scrollSnapType: 'y proximity', // 使用 proximity 吸附功能
          '&::-webkit-scrollbar': { display: 'none' }, // 隐藏滚动条
        }}
      >
        <List sx={{ padding: 0, margin: 0 }}>
          {/* 上方的占位元素 */}
          <ListItem
            sx={{
              height: '80px', // 高度设置为遮罩区两倍
            }}
          />
          {range.map((value, index) => (
            <ListItem
              key={index}
              sx={{
                height: '40px',
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                scrollSnapAlign: 'center',
                scrollSnapStop: 'always', // 确保滚动停止在每个元素上
                fontSize: '20px',
                color: index === 0 || index === range.length - 1 ? '#888' : '#fff',
              }}
              onClick={() => onSelect(value)}
            >
              {value}
            </ListItem>
          ))}
          {/* 下方的占位元素 */}
          <ListItem
            sx={{
              height: '80px', // 高度设置为遮罩区两倍
            }}
          />
        </List>
      </Box>

      {/* 遮罩Box被放置在容器Box的外部 */}
      <Box
        sx={{
          position: 'absolute',
          top: '50%',
          left: 0,
          right: 0,
          height: '40px',
          marginTop: '-20px',
          backgroundColor: 'rgba(255, 255, 255, 0.1)', // 设置遮罩的颜色
          pointerEvents: 'none',
          border: '2px solid #1976d2',
          borderRadius: '4px',
          zIndex: 1, // 确保遮罩在列表项之上
        }}
      />
    </Box>
  );
};

export default WheelPicker;

111.png