如何在Next.js + Tailwind项目中实现Figma设计的步骤组件?
Next.js + Tailwind 实现步骤展示模块的思路
结合你的技术栈,以下几种落地性强的实现思路可以参考:
1. 静态硬编码(适合固定步骤场景)
如果步骤数量和内容不会变动,直接用JSX编写结构,配合Tailwind快速完成样式:
- 用
flex垂直排列每个步骤项,左侧放编号容器(用rounded-full实现圆形样式),右侧承载标题和描述 - 步骤间的连线通过绝对定位元素实现:给非最后一步的步骤项添加相对定位,内部嵌入一条垂直细线作为连接
示例代码:
<div className="space-y-6"> {/* 步骤1 */} <div className="flex items-start relative"> <div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white">1</div> <div className="ml-4"> <h3 className="font-semibold text-lg">第一步标题</h3> <p className="text-gray-600 mt-1">这是第一步的操作说明,清晰描述步骤要点</p> </div> <div className="absolute left-5 top-10 bottom-0 w-px bg-gray-300"></div> </div> {/* 步骤2 */} <div className="flex items-start relative"> <div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white">2</div> <div className="ml-4"> <h3 className="font-semibold text-lg">第二步标题</h3> <p className="text-gray-600 mt-1">这是第二步的操作说明,清晰描述步骤要点</p> </div> <div className="absolute left-5 top-10 bottom-0 w-px bg-gray-300"></div> </div> {/* 步骤3(无连接线) */} <div className="flex items-start"> <div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white">3</div> <div className="ml-4"> <h3 className="font-semibold text-lg">第三步标题</h3> <p className="text-gray-600 mt-1">这是第三步的操作说明,清晰描述步骤要点</p> </div> </div> </div>
2. 数据驱动渲染(适合动态/可配置步骤)
如果步骤需要从接口获取或后续可能修改,把数据抽象成数组,通过map循环渲染:
- 可以在组件内定义静态数组,也可以通过Next.js的
getStaticProps/getServerSideProps从后端拉取数据 - 循环时通过条件判断自动控制连接线的显隐,避免重复写冗余代码
示例代码:
const steps = [ { id: 1, title: "第一步标题", desc: "这是第一步的操作说明,清晰描述步骤要点" }, { id: 2, title: "第二步标题", desc: "这是第二步的操作说明,清晰描述步骤要点" }, { id: 3, title: "第三步标题", desc: "这是第三步的操作说明,清晰描述步骤要点" }, ]; export default function StepsModule() { return ( <div className="space-y-6"> {steps.map((step, index) => ( <div key={step.id} className={`flex items-start ${index !== steps.length - 1 ? 'relative' : ''}`}> <div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white">{step.id}</div> <div className="ml-4"> <h3 className="font-semibold text-lg">{step.title}</h3> <p className="text-gray-600 mt-1">{step.desc}</p> </div> {index !== steps.length - 1 && ( <div className="absolute left-5 top-10 bottom-0 w-px bg-gray-300"></div> )} </div> ))} </div> ); }
3. 组件化封装(高复用性场景)
如果项目多个页面需要步骤模块,把单个步骤封装成独立组件,通过props传递状态和内容:
- 封装
StepItem组件,接收number、title、desc、isLast、isActive等参数,动态切换样式 - 父组件统一管理步骤数据和激活状态,批量调用子组件即可
示例代码:
// components/StepItem.jsx export default function StepItem({ number, title, desc, isLast, isActive = false }) { const numberBg = isActive ? 'bg-blue-600' : 'bg-gray-300'; const numberText = isActive ? 'text-white' : 'text-gray-700'; return ( <div className={`flex items-start ${!isLast ? 'relative' : ''}`}> <div className={`w-10 h-10 rounded-full ${numberBg} flex items-center justify-center ${numberText}`}> {number} </div> <div className="ml-4"> <h3 className={`font-semibold text-lg ${isActive ? 'text-blue-600' : ''}`}>{title}</h3> <p className="text-gray-600 mt-1">{desc}</p> </div> {!isLast && ( <div className="absolute left-5 top-10 bottom-0 w-px bg-gray-300"></div> )} </div> ); } // 父组件使用 import StepItem from '@/components/StepItem'; import { useState } from 'react'; const steps = [/* 步骤数据 */]; export default function StepsModule() { const [activeStep, setActiveStep] = useState(1); return ( <div className="space-y-6"> {steps.map((step, index) => ( <StepItem key={step.id} number={step.id} title={step.title} desc={step.desc} isLast={index === steps.length - 1} isActive={step.id === activeStep} onClick={() => setActiveStep(step.id)} /> ))} </div> ); }
4. 交互增强(带状态切换/滚动触发)
如果需要实现点击切换、滚动激活等交互:
- 用
useState管理当前激活步骤,点击时更新状态并切换样式 - 滚动激活可以借助
react-intersection-observer的useInView钩子,监听步骤项是否进入视口,自动激活对应步骤
示例(滚动激活核心代码):
import { useInView } from 'react-intersection-observer'; export default function StepItem({ number, title, desc, isLast }) { const [ref, inView] = useInView({ threshold: 0.5, triggerOnce: true, }); const numberBg = inView ? 'bg-blue-600' : 'bg-gray-300'; const numberText = inView ? 'text-white' : 'text-gray-700'; return ( <div ref={ref} className={`flex items-start ${!isLast ? 'relative' : ''}`}> {/* 内容结构同上 */} </div> ); }
额外优化点
- 响应式适配:用Tailwind的
sm:/md:前缀,在移动端调整布局(比如改为水平排列) - 动画效果:配合
transition类,给激活状态添加平滑过渡(比如背景色渐变)
内容的提问来源于stack exchange,提问作者Hosea Kibet
相关产品推荐
相关产品推荐

