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

React中使用useRef获取img高度动态设置SVG高度的方法

实现方案

你判断的方向没错,用useRef配合尺寸监听就能实现,核心逻辑是:

  • 用ref绑定图片元素,避免直接操作DOM的时序问题
  • 监听图片加载完成事件、图片元素尺寸变化事件,实时计算图片高度的90%
  • 把计算出的高度传给SVG组件,利用SVG自带的viewBox属性自动适配比例,不会变形
  • 父容器设置相对定位,SVG层设置绝对定位叠在图片上层,不占用文档流

具体代码修改

1. 父组件Polska修改

import { useState, useRef, useEffect } from 'react'
import { Row, Col, Tooltip } from 'antd' // 按你项目实际导入路径调整
import classNames from 'classnames'
import Wisla from './Wisla'

export const Polska = () => {
  const [riverVisible, setRiverVisible] = useState(false)
  // 绑定轮廓图片的ref
  const contourImgRef = useRef(null)
  // 存储计算后的SVG高度
  const [wislaHeight, setWislaHeight] = useState(0)

  useEffect(() => {
    const imgNode = contourImgRef.current
    if (!imgNode) return

    // 尺寸同步逻辑
    const syncSvgSize = () => {
      setWislaHeight(imgNode.clientHeight * 0.9)
    }

    // 图片加载完成后执行首次计算
    if (imgNode.complete) {
      syncSvgSize()
    } else {
      imgNode.onload = syncSvgSize
    }

    // 监听图片尺寸变化(响应式断点切换、窗口缩放、容器变动都会触发)
    const observer = new ResizeObserver(syncSvgSize)
    observer.observe(imgNode)

    // 组件卸载时清理监听,避免内存泄漏
    return () => {
      observer.disconnect()
      imgNode.onload = null
    }
  }, [])

  return (
    <div>
      <Row>
        <Col className='list-of-landscapes' sm={12} md={2} >
            <ul>
                <li>
                  <button onClick={() => setRiverVisible(!riverVisible)}>rzeki</button>
                </li>
                <li>
                  <button>jeziora</button>
                </li>
            </ul>
        </Col>
        {/* 父容器设相对定位,作为SVG绝对定位的参照 */}
        <Col sm={12} md={10} className="rivers-box" style={{ position: 'relative' }}>
          <img 
            ref={contourImgRef}
            className='contour' 
            src="images/polska-kontur.jpg" 
            alt='polska'
            style={{ width: '100%', display: 'block' }}
          />
          {/* SVG层绝对定位,居中叠在图片上方 */}
          <Col 
            className='rivers' 
            style={{ 
              position: 'absolute', 
              top: '5%', 
              left: 0, 
              width: '100%', 
              display: 'flex', 
              justifyContent: 'center' 
            }}
          >
            <Wisla riverVisible={riverVisible} height={wislaHeight} />
          </Col> 
        </Col>
      </Row>
    </div>
  )
}

export default Polska

2. 子组件Wisla修改

只需要接收父组件传入的高度,直接绑定到SVG元素上即可:

export const Wisla = ({riverVisible, height}) => {
    return (
        <svg 
          id='wisla-id' 
          className={classNames('wisla', riverVisible && "visible")} 
          xmlns="http://www.w3.org/2000/svg" 
          viewBox="0 0 312.47 625.89"
          style={{ height: height }}
        >
            <g id="Warstwa_2" dataName="Warstwa 2">
                <g id="Warstwa_2-2" dataName="Warstwa 2">
                    <Tooltip title='wisla wisla wisla wisla wisla wisla wisla wisla' followCursor>
                        <path
                            className="cls-wisla"
                            d="M67.06,0V22.72l-6,6.14v52.8l-6.6,8.6v16l-6,11.67-13.8,6.75L4.06,162.1l45.6,19,9,17.19,15,19,28.2,10.43,48,
                            23.34,4.8,5.52h27l10.8-5.52,17.4,2.45,25.8,23.33,15,43.16,10.8,7.19,5.4,21.49,33,16,9.6,25.78-12,8.6,6.6,73.68-21,
                            25.79-31.2,19.65-21.6,8-7.2,8.59h-9l-13.2,14.74h-15.6l-9,8.6h-6.6l-2.4,7.36h-30.6l-5.4,6.32-12.6,
                            2.89-13.2-8.59-13.2-2.46-9.6.62-7.2,10.43-24,6.14.6,12.28,2.4,22.11,12.6,8.59">
                        </path>
                    </Tooltip>
                </g>
            </g>
        </svg>
    )
}

注意事项

  • 不要用document.getElementById获取DOM,React中用useRef绑定元素可以避免渲染时序、id重复导致的取值错误
  • 必须监听图片的onload事件,否则图片未加载完成时取到的高度为0,会导致SVG不显示
  • 用ResizeObserver监听元素尺寸比监听window.resize更可靠,栅格断点切换、父容器大小变动等场景都能触发同步
  • 因为SVG已经设置了viewBox属性,只需要指定高度,宽度会自动按原始比例缩放,不会出现拉伸变形
  • 代码里的内联样式可以迁移到对应的CSS文件中,不影响功能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:24:28