You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React可滚动modal如何识别当前可视元素并更新对应elm变量

实现方案

核心采用浏览器原生IntersectionObserver接口实现可视元素检测,相比手动计算滚动位置的方案,准确率更高、兼容性更好,也能避免布局偏移导致的计算误差。

import { useState, useRef, useEffect } from 'react'

const Modal = (props) => {
  const [elm, setElm] = useState(0)
  // 存储所有待检测元素的ref
  const itemRefs = useRef([])
  // 滚动容器ref
  const scrollContainerRef = useRef(null)

  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const index = itemRefs.current.indexOf(entry.target)
          if (index !== -1 && entry.intersectionRatio >= 0.5) {
            // 元素可见比例超过50%时更新序号,阈值可自行调整
            setElm(index)
          }
        }
      })
    }, {
      root: scrollContainerRef.current,
      threshold: [0, 0.5, 1]
    })

    itemRefs.current.forEach(item => item && observer.observe(item))
    return () => observer.disconnect()
  }, [])

  return (
    <div 
      ref={scrollContainerRef}
      style={{ 
        height: '400px',
        overflowY: 'auto',
        border: '1px solid #eee'
      }}
    >
      <p>Current element is: {elm}</p>
      <div ref={el => itemRefs.current[0] = el}>element1 内容</div>
      <div ref={el => itemRefs.current[1] = el}>element2 内容</div>
      <div ref={el => itemRefs.current[2] = el}>element3 内容</div>
      <div ref={el => itemRefs.current[3] = el}>element4 内容</div>
    </div>
  )
}

注意事项

  • 自定义可见规则可调整threshold参数与intersectionRatio判断阈值,如需元素完全可见才更新,将阈值设为1即可
  • 动态元素可在遍历渲染时绑定ref,无需手动逐个指定序号
  • 如果element1~element4是自定义函数组件,需要使用forwardRef包裹组件接收ref参数,否则无法绑定DOM节点
  • 若仍要使用手动计算滚动位置的方案,需保证滚动容器为定位元素(添加position: relative属性),计算时取scrollTop + 容器可视高度/2与各元素offsetTop值对比,取最接近的值对应序号即可

内容的提问来源于stack exchange,提问作者Mladen Milosavljevic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 09:06:02