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

React中如何在两个div(或两个点)之间绘制连接线?

React实现任意Div圆点间连线的方案

3×3网格排列的9个圆形,其中3个圆形通过随机线条连接至其他圆形(示例图)

最推荐:零依赖SVG叠加层方案

不需要引入任何第三方库,天然支持水平、垂直、任意角度斜线,逻辑完全可控,不会出现第三方库不渲染的问题。

实现逻辑

  • 外层3x3网格容器设置position: relative
  • 容器内部嵌入和容器尺寸完全一致的SVG层,设置position: absolute; top: 0; left: 0; pointer-events: none,z-index低于圆点,避免遮挡交互
  • 所有圆点设置position: relative,z-index高于SVG层,保证圆点显示在连线之上
  • DOM渲染完成后,获取每对需要连接的圆点的中心坐标(相对于SVG容器的偏移量),直接在SVG内绘制<line>标签即可

最小可运行代码示例

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

// 3x3网格圆点配置
const dotList = [
  { id: 1, row: 0, col: 0 }, { id: 2, row: 0, col: 1 }, { id: 3, row: 0, col: 2 },
  { id: 4, row: 1, col: 0 }, { id: 5, row: 1, col: 1 }, { id: 6, row: 1, col: 2 },
  { id: 7, row: 2, col: 0 }, { id: 8, row: 2, col: 1 }, { id: 9, row: 2, col: 2 },
]
// 需要连线的圆点ID对
const connectPairs = [[1, 5], [5, 9], [3, 7]]

export default function DotGrid() {
  const gridRef = useRef(null)
  const dotDomRefs = useRef({})
  const [lineConfigs, setLineConfigs] = useState([])

  useEffect(() => {
    const gridRect = gridRef.current.getBoundingClientRect()
    const lines = connectPairs.map(([fromId, toId]) => {
      const fromDom = dotDomRefs.current[fromId]
      const toDom = dotDomRefs.current[toId]
      const fromRect = fromDom.getBoundingClientRect()
      const toRect = toDom.getBoundingClientRect()

      // 计算两个圆点相对于SVG画布的中心坐标
      return {
        x1: fromRect.left - gridRect.left + fromRect.width / 2,
        y1: fromRect.top - gridRect.top + fromRect.height / 2,
        x2: toRect.left - gridRect.left + toRect.width / 2,
        y2: toRect.top - gridRect.top + toRect.height / 2,
      }
    })
    setLineConfigs(lines)
  }, [])

  return (
    <div 
      ref={gridRef} 
      className="grid grid-cols-3 gap-16 p-8 relative w-fit"
    >
      {/* SVG连线层 */}
      <svg 
        className="absolute top-0 left-0 w-full h-full pointer-events-none" 
        style={{ zIndex: 0 }}
      >
        {lineConfigs.map((line, idx) => (
          <line
            key={idx}
            x1={line.x1}
            y1={line.y1}
            x2={line.x2}
            y2={line.y2}
            stroke="#222"
            strokeWidth="2"
          />
        ))}
      </svg>

      {/* 圆点层 */}
      {dotList.map(dot => (
        <div
          key={dot.id}
          ref={dom => (dotDomRefs.current[dot.id] = dom)}
          className="w-8 h-8 rounded-full bg-gray-900"
          style={{ zIndex: 1 }}
        />
      ))}
    </div>
  )
}

如果是固定布局的静态连线,甚至不需要动态计算DOM坐标,直接根据网格的单元格宽高、间距写死连线坐标即可,代码会更简洁。这个方案支持自定义线的样式,虚线、渐变、箭头、连线动画都可以直接通过SVG属性实现。

备选:成熟第三方连线库

如果后续需要支持拖拽连线、元素拖动时连线自动跟随、连线避障等复杂交互,可以选择维护状态更好的库:

  • reactflow:功能最完善的React节点连线库,适合做流程图、拓扑图类场景
  • react-konva:基于Canvas的绘图库,如果需要大量连线、图形元素时性能比SVG更好

之前react-lineto不渲染的常见原因

你之前写的测试代码不渲染,基本是几个低级问题导致的:

  • 对应from、to类名的元素没有设置position: relative,库无法获取正确的元素位置
  • <LineTo />组件没有放在两个目标元素的共同父容器内部
  • 类名为B的div没有设置宽高,嵌套的空div没有承接类名,库无法定位到目标元素

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 07:24:28