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

如何用ReactJS和TailwindCSS实现斜向曲线响应式时间线?

实现从左下角到右上角的曲线时间线(React + Tailwind CSS)

核心思路

利用SVG绘制可缩放的贝塞尔曲线作为时间线主体,通过JavaScript计算曲线上的坐标点定位时间节点,结合Tailwind CSS实现响应式布局与样式优化。

完整代码实现

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

const CurvedTimeline = () => {
  const pathRef = useRef(null);
  const [itemPositions, setItemPositions] = useState([]);

  // 时间线节点数据
  const timelineItems = [
    { id: 1, title: "项目启动", content: "确定项目需求与核心目标" },
    { id: 2, title: "原型设计", content: "完成产品交互原型与视觉设计" },
    { id: 3, title: "开发阶段", content: "核心功能开发与内部测试" },
    { id: 4, title: "Beta发布", content: "面向测试用户开放体验" },
    { id: 5, title: "正式上线", content: "产品全量发布并持续迭代" },
  ];

  // 计算节点在曲线上的位置
  const calculatePositions = () => {
    if (!pathRef.current) return;
    const path = pathRef.current;
    const totalLength = path.getTotalLength();
    const positions = timelineItems.map((_, index) => {
      // 均匀分布节点,首尾预留空间避免堆积
      const fraction = (index + 1) / (timelineItems.length + 1);
      const point = path.getPointAtLength(totalLength * fraction);
      return { x: point.x, y: point.y };
    });
    setItemPositions(positions);
  };

  // 初始化与窗口 resize 时重新计算位置
  useEffect(() => {
    calculatePositions();
    window.addEventListener('resize', calculatePositions);
    return () => window.removeEventListener('resize', calculatePositions);
  }, [timelineItems.length]);

  return (
    <div className="relative min-h-screen w-full p-4 md:p-8">
      {/* SVG 曲线时间线 */}
      <svg ref={pathRef} className="absolute inset-0 w-full h-full pointer-events-none">
        <path
          d="M 2% 98% C 25% 75%, 75% 25%, 98% 2%"
          stroke="#3b82f6"
          strokeWidth="3"
          fill="none"
          strokeLinecap="round"
        />
      </svg>

      {/* 时间线节点 */}
      {timelineItems.map((item, index) => (
        <div
          key={item.id}
          className="absolute bg-white rounded-lg shadow-lg p-4 max-w-xs md:max-w-sm transition-all hover:shadow-xl"
          style={
            itemPositions[index]
              ? {
                  left: `${itemPositions[index].x}px`,
                  top: `${itemPositions[index].y}px`,
                  transform: 'translate(-50%, -50%)',
                }
              : {}
          }
        >
          <div className="w-6 h-6 rounded-full bg-blue-500 mb-2 mx-auto"></div>
          <h3 className="font-bold text-lg text-gray-800">{item.title}</h3>
          <p className="text-gray-600 mt-1">{item.content}</p>
        </div>
      ))}
    </div>
  );
};

export default CurvedTimeline;

关键细节说明

  1. SVG曲线设计

    • 使用三次贝塞尔曲线(C指令),坐标采用百分比单位,确保曲线随容器自适应缩放
    • M 2% 98%定义起点(左下角),C 25% 75%, 75% 25%, 98% 2%定义两个控制点和终点(右上角),调整控制点可灵活改变曲线弧度
  2. 节点定位逻辑

    • 通过path.getTotalLength()获取曲线总长度,path.getPointAtLength()获取指定长度处的坐标
    • 按(index+1)/(总节点数+1)的比例均匀分配节点,避免节点堆积在曲线两端
  3. 响应式处理

    • 监听窗口resize事件,重新计算节点位置,确保始终贴合曲线
    • Tailwind的max-w-xs/max-w-sm等类实现节点在不同屏幕尺寸下的自适应宽度
  4. 样式优化

    • 节点使用translate(-50%, -50%)实现基于曲线点的居中定位
    • 添加pointer-events-none到SVG,避免遮挡节点的交互事件
    • hover阴影效果提升交互体验

扩展优化建议

  • 防抖处理:为resize事件添加防抖函数,减少频繁计算带来的性能消耗
  • 自定义曲线:允许通过props传递曲线的控制点参数,实现不同形状的时间线
  • 节点连接:为每个节点添加指向曲线的箭头或连线,增强视觉关联
  • 动画效果:添加节点进入动画或滚动触发的显示效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 21:15:47