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

React JS动态元素ID平滑滚动的代码优化方案

优化多组件平滑滚动,无需逐个声明ref

需求:点击Next/Prev按钮时实现平滑滚动效果,当前需要手动为每个组件声明ref,希望找到无需逐个声明ref的优化方法。

当前代码:

const aRef = useRef(null);
const bRef = useRef(null);
const cRef = useRef(null);

const scrollTo = (id: any) => {
  console.log(id);
  scrollToComponent(id);
};

const renderA = () => {
  return (
    <div ref={aRef} className="step" id="A">
      <h1>Component A</h1>
      <button className="next" onClick={() => scrollTo(bRef.current)}>
        NEXT
      </button>
    </div>
  );
};

const renderB = () => {
  return (
    <div ref={bRef} className="step" id="B">
      <h1>Component B</h1>
      <button className="next" onClick={() => scrollTo(cRef.current)}>
        NEXT
      </button>
      <button className="next" onClick={() => scrollTo(aRef.current)}>
        PREV
      </button>
    </div>
  );
};

return (
  <div>
    {renderA()}
    {renderB()}
    {renderC()}
  </div>
);

方法1:利用元素ID + scrollIntoView(最简洁)

完全不需要声明ref,直接借助元素的id属性,结合原生scrollIntoView的平滑配置实现滚动。

修改后的核心代码:

// 滚动函数:接收目标元素ID
const scrollTo = (targetId: string) => {
  const targetEl = document.getElementById(targetId);
  targetEl?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};

// 组件A
const renderA = () => {
  return (
    <div className="step" id="A">
      <h1>Component A</h1>
      <button className="next" onClick={() => scrollTo('B')}>
        NEXT
      </button>
    </div>
  );
};

// 组件B
const renderB = () => {
  return (
    <div className="step" id="B">
      <h1>Component B</h1>
      <button className="next" onClick={() => scrollTo('C')}>
        NEXT
      </button>
      <button className="prev" onClick={() => scrollTo('A')}>
        PREV
      </button>
    </div>
  );
};

优势:无需维护任何ref,利用原生DOM查询实现,代码极简,适合大多数场景。


方法2:用单个Ref统一管理所有组件

如果希望通过ref而非DOM查询管理元素,可以用一个对象类型的ref存储所有组件元素,避免逐个声明ref。

核心代码:

import { useRef } from 'react';

// 用对象ref存储所有组件元素
const stepRefs = useRef<Record<string, HTMLElement | null>>({});

const scrollTo = (targetId: string) => {
  const targetEl = stepRefs.current[targetId];
  targetEl?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};

const renderA = () => {
  return (
    <div 
      ref={el => stepRefs.current['A'] = el} 
      className="step" 
      id="A"
    >
      <h1>Component A</h1>
      <button className="next" onClick={() => scrollTo('B')}>
        NEXT
      </button>
    </div>
  );
};

const renderB = () => {
  return (
    <div 
      ref={el => stepRefs.current['B'] = el} 
      className="step" 
      id="B"
    >
      <h1>Component B</h1>
      <button className="next" onClick={() => scrollTo('C')}>
        NEXT
      </button>
      <button className="prev" onClick={() => scrollTo('A')}>
        PREV
      </button>
    </div>
  );
};

优势:所有组件元素统一管理,避免零散的ref变量,适合需要对组件元素做额外操作的场景。


方法3:动态生成组件(适合多组件场景)

如果组件数量较多,推荐把组件数据抽象成数组,循环渲染并自动绑定导航逻辑,彻底告别手动编写重复代码。

核心代码:

import { useRef } from 'react';

// 定义所有步骤的配置数据
const steps = [
  { id: 'A', title: 'Component A', nextId: 'B', prevId: null },
  { id: 'B', title: 'Component B', nextId: 'C', prevId: 'A' },
  { id: 'C', title: 'Component C', nextId: null, prevId: 'B' },
];

const stepRefs = useRef<Record<string, HTMLElement | null>>({});

const scrollTo = (targetId: string) => {
  const targetEl = stepRefs.current[targetId];
  targetEl?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};

return (
  <div>
    {steps.map(step => (
      <div
        key={step.id}
        ref={el => stepRefs.current[step.id] = el}
        className="step"
        id={step.id}
      >
        <h1>{step.title}</h1>
        {step.nextId && (
          <button className="next" onClick={() => scrollTo(step.nextId)}>
            NEXT
          </button>
        )}
        {step.prevId && (
          <button className="prev" onClick={() => scrollTo(step.prevId)}>
            PREV
          </button>
        )}
      </div>
    ))}
  </div>
);

优势:扩展性极强,新增/删除组件只需修改steps数组,无需改动渲染逻辑,代码复用率高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:10:35