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
相关产品推荐
相关产品推荐

