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

使用Refs获取React Tabs元素尺寸实现激活态底部滑块跟随效果

Tabs 滑块位置计算问题修复

核心问题梳理

  • 违反React Hook调用规则:不能在map循环中调用useRef,Hook只能在组件顶层作用域调用
  • Ref使用逻辑错误:tabsRef是循环生成的ref数组,数组本身没有current属性,只有数组内每个单独的ref实例才有current指向DOM元素
  • 变量名拼写错误:定义的状态更新函数是setSliderInfo,实际调用写成了setSliderWidth,会直接抛出未定义错误
  • 依赖项配置错误:tabsRef每次组件渲染都会重新生成新数组,会导致useEffect无限触发,且需要监听的是激活态value的变化,切换Tab时才需要更新滑块位置
  • 定位值计算逻辑缺失:滑块是相对于父容器StyledTabsContainer绝对定位,直接取Tab元素相对于视口的left会导致定位错位,需要减去父容器的左偏移量得到相对位置

修复后代码

const Tabs = ({renderTab, options, value}) => {   
  // option是存储每个Tab配置的数组,value是当前激活Tab的状态值
  const [sliderInfo, setSliderInfo] = useState({width: 0, left: 0});
  // 存储所有Tab的DOM引用,单个ref存储数组,不要在循环内调用useRef
  const tabsRef = useRef(new Array(options.length).fill(null));
  // 父容器ref,用于计算相对偏移
  const containerRef = useRef(null);

  const currentTab = options.findIndex((tab) => tab.value === value );  

  // 计算滑块位置的公共方法
  const updateSliderPosition = () => {
    if (currentTab < 0 || !tabsRef.current[currentTab] || !containerRef.current) return;
    const tabRect = tabsRef.current[currentTab].getBoundingClientRect();
    const containerRect = containerRef.current.getBoundingClientRect();
    setSliderInfo({
      width: tabRect.width,
      // 计算相对于父容器的左偏移
      left: tabRect.left - containerRect.left
    });
  };

  // 激活Tab变化、组件挂载、options变化时更新滑块
  useEffect(() => {
    updateSliderPosition();
    // 窗口尺寸变化时也要更新滑块位置
    window.addEventListener('resize', updateSliderPosition);
    return () => window.removeEventListener('resize', updateSliderPosition);
  }, [value, options]);

  return (
    <StyledTabsContainer ref={containerRef}>
      {options.map((tab, i) => {  
        return (
          <div 
            key={i} 
            className='wrapper' 
            ref={(el) => tabsRef.current[i] = el} 
          >
            { renderTab(tab) }
          </div>            
        )
      })}
      <TabSlider width={sliderInfo.width} left={sliderInfo.left} />
    </StyledTabsContainer>
  )
}

补充说明

如果你的TabSlider需要实现流畅的切换过渡,给滑块添加transition: all 0.3s ease类CSS属性即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:24:04