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

React中使用CSS变量动态修改动画属性触发只读错误如何解决

错误原因

React 会将传递给 style 属性的对象冻结为只读状态,你在 onAnimationEnd 回调中直接修改 cssProperties 对象的属性,就会触发只读报错。同时直接修改普通变量不会触发 React 组件重新渲染,即使没有报错,样式也不会更新,动画参数不会生效。

解决方案

将所有动态的动画 CSS 变量放到 React state 中管理,动画结束后通过 setState 更新参数触发重新渲染,同时新增 key 属性保证动画每次更新参数后都能重新运行,避免动画不触发的问题。

修改后的组件代码如下:

class HotAir extends React.Component{
  constructor(props){  
    super(props);  
    this.state = {
      link: props.link,
      cls: props.cls,
      img: props.img,
      text: props.text,
      // 动画相关参数全部放入state管理
      animationTime: `${Math.random()*10 + 2}s`,
      xStart: `${Math.random()*10 + 5}vw`,
      yStart: `${Math.random()*10 + 5}vh`,
      xEnd: `${Math.random()*70 + 20}vw`,
      yEnd: `${Math.random()*70 + 20}vh`
    }
    this.handleAnimationEnd = this.handleAnimationEnd.bind(this)
  }  

  handleAnimationEnd() {
    // 动画结束后生成新的随机参数,setState触发重渲染
    this.setState({
      animationTime: `${Math.random()*10 + 2}s`,
      // 下次动画起始位置承接上次结束位置,移动更连贯
      xStart: this.state.xEnd,
      yStart: this.state.yEnd,
      xEnd: `${Math.random()*70 + 20}vw`,
      yEnd: `${Math.random()*70 + 20}vh`
    })
  }

  render(){
    const cssProperties = {
      '--animation-time': this.state.animationTime,
      '--x-float-start': this.state.xStart,
      '--y-float-start': this.state.yStart,
      '--x-float-end': this.state.xEnd,
      '--y-float-end': this.state.yEnd
    };
    // 用参数拼接key,参数变化时React重建元素保证动画重新触发
    const elementKey = `${this.state.animationTime}-${this.state.xStart}-${this.state.yEnd}`
    
    return(
      <div 
        key={elementKey}
        className="balloon" 
        style={cssProperties} 
        onAnimationEnd={this.handleAnimationEnd}
      >
        <Link to={this.state.link}>
          <button className="balloonbutt">
            <img src={this.state.img} alt="热气球按钮"/>
            <div className="balloontext">{this.state.text}</div>
          </button>
        </Link>
      </div>
    );
  }
}

调整后的CSS代码(新增属性保证动画结束后保持最后一帧状态,避免跳回初始位置):

.balloon{
    --animation-time: 60s;
    --x-float-start: 10vw;
    --y-float-start: 10vh;
    --x-float-end: 20vw;
    --y-float-end: 20vh;
    position: relative;
    text-align: center;
    color: white;
    animation: float var(--animation-time) linear;
    animation-fill-mode: forwards;
}
@keyframes float{
    0%{
        left: var(--x-float-start);
        top: var(--y-float-start);
    }
    100%{
        left: var(--x-float-end);
        top: var(--y-float-end);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 03:18:03