其他分享
首页 > 其他分享> > React 实现鼠标水平滚动组件

React 实现鼠标水平滚动组件

作者:互联网

实现要点

实现步骤

页面布局

事件监听

注意事项

元素滚动

参考代码

import { createStyles, withStyles } from '@material-ui/core/styles'
import { SitePropsType } from 'components/base/Site'
import { useEffect, useRef } from 'react'

const styles = createStyles({
  root: {
    overflowX: 'auto',
  },
  container: {
    display: 'flex',
    flexWrap: 'nowrap',
    overflowX: 'auto',
  },
  item: {
    height: '300px',
    width: '100%',
    backgroundColor: '#f0f0f0',
    border: '1px solid #333333',
    flexShrink: 0,
    // '&:hover': {
    //   cursor: 'pointer',
    // },
  },
  indicator: {},
})

interface SiteSwiperProps {
  classes?: {
    root: string
    container: string
    item: string
    indicator: string
  }
  sites: SitePropsType[]
  row?: number
}

/**
 * 计算滚动位置
 * @param currentScrollLeft
 * @param scrollElWith
 */
const computeScroll = (
  currentScrollLeft: number,
  scrollElWith: number
): number => {
  // 判断滚动偏移是否满足滚动要求
  console.log('current scroll left:', currentScrollLeft)
  const index = Math.round(currentScrollLeft / scrollElWith)
  return scrollElWith * index
}

function SiteSwiper({ classes, sites, row = 3 }: SiteSwiperProps): JSX.Element {
  const containerRef = useRef(null)
  const timer = useRef(null)

  useEffect(() => {
    console.log('current ref:', containerRef)
    containerRef.current.addEventListener('wheel', (e) => {
      console.log('mouse wheel event:', e)
      // 阻止原生滚动事件
      e.preventDefault()

      // 获取滚动位置
      let scrollLeft = containerRef.current.scrollLeft
      const scrollTotalWidth = containerRef.current.scrollWidth
      const scrollItemWidth = containerRef.current.offsetWidth

      // 获取容器的宽度
      console.log(
        'current container:',
        containerRef.current.offsetWidth,
        e.deltaY
      )
      // 即时水平滚动偏移值
      const bufferOffset = 70
      const scrollBehavior = 'smooth'
      let offset = scrollLeft + e.deltaY * 4 // 放大偏移倍数
      if (offset >= scrollTotalWidth - scrollItemWidth + bufferOffset) {
        // 到达最后元素
        offset = offset - scrollTotalWidth - bufferOffset
        // scrollBehavior = 'auto'
      } else if (offset + bufferOffset < 0) {
        // 达到第一元素
        offset = scrollTotalWidth + offset - bufferOffset
        // scrollBehavior = 'auto'
      } else {
        // 其它情况
      }
      console.log('offset y at time:', scrollLeft, offset)
      containerRef.current.scrollTo({
        top: 0,
        left: offset,
        behavior: scrollBehavior,
      })

      // 防抖
      if (timer.current) {
        clearTimeout(timer.current)
      }

      timer.current = setTimeout(() => {
        // 计算滚动最后的位置进行位置矫正
        console.log('TIME OUT: starting position correct...')
        // 计算是否滚动
        scrollLeft = computeScroll(offset, scrollItemWidth)

        containerRef.current.scrollTo({
          top: 0,
          left: scrollLeft,
          behavior: 'smooth',
        })
      }, 700)
    })
  })

  return (
    <div className={classes.root} id="swiper-container">
      {/* Content */}
      <div
        className={classes.container}
        // onScroll={handleMouseScroll}
        // onm ouseOver={handleMouseOver}
        // onWheel={handleWheel}
        ref={containerRef}
      >
        {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((item) => (
          <div className={`${classes.item} swiper-item`} key={item}>
            {item}
          </div>
        ))}
      </div>

      {/* Indicator */}
      <div className={classes.indicator}></div>
    </div>
  )
}

export default withStyles(styles)(SiteSwiper)

标签:current,containerRef,滚动,鼠标,scrollLeft,React,offset,组件,const
来源: https://www.cnblogs.com/li1234yun/p/14529894.html