【问题标题】:ReactJS, CSS and SVG animations, and re-renderingReactJS、CSS 和 SVG 动画,以及重新渲染
【发布时间】:2018-06-19 03:12:20
【问题描述】:

可以在此处查看问题的实际效果:
https://codepen.io/fsabe/pen/opEVNR?editors=0110

第一次加载时,您会看到蓝色圆圈在周围旋转,而红色框逐渐淡入淡入。
圆圈通过 svg 标签制作动画,盒子通过 css 动画制作。
如果单击画布上的任意位置,代码会触发重新渲染,可以通过打开控制台来验证。

我的期望是两个动画都会在点击时重置,但这并没有发生。
我有一种预感,这与缓存和 react 的 shadow DOM 有关。

为什么会这样?如何解决?

代码如下:

#nonSvgBox {
  animation-duration: 1s;
  animation-name: fade;
  width: 100px;
  height: 100px;
  background-color: red;
}

@keyframes fade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
class Component extends React.Component {
  onClick() {
    this.setState({a: 1});
  }

  render() {
    console.log('rendering');
    return (
      <div onClick={() => this.onClick()}>
        <svg>
          <path 
            stroke="blue"
            strokeWidth="10"
            fill="transparent"
            d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"
            strokeDasharray="251.2,251.2">
            <animate
              attributeType="css"
              attributeName="stroke-dasharray"
              from="0" to="251.2" dur="1s" />
          </path>
        </svg>
        <div id="nonSvgBox"></div>
      </div>
    );
  }
}

ReactDOM.render(<Component />, document.getElementById('app'));

谢谢。

【问题讨论】:

    标签: javascript css reactjs svg


    【解决方案1】:

    React 正在重用元素,因此动画不会重播它们已经为当前元素播放的 b/c。

    我认为在这种情况下使用 dom 操作比一些setState 诡计更容易。

    https://codepen.io/guanzo/pen/vpdPzX?editors=0110

    将 refs 存储到 2 个元素,然后用 JS 触发动画。

    class Component extends React.Component {
      onClick() {
        this.svgAnimate.beginElement()//triggers animation
        this.square.style.animation = 'none';//override css animation
        this.square.offsetHeight; /* trigger reflow */
        this.square.style.animation = null; //fallback to css animation
      }
    
        render() {
        console.log('rendering');
            return (
                <div onClick={() => this.onClick()}>
                    <svg>
                        <path 
                            stroke="blue"
                strokeWidth="10"
                            fill="transparent"
                            d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80"
                strokeDasharray="251.2,251.2">
                  <animate
                    ref={(svgAnimate) => { this.svgAnimate = svgAnimate; }} 
                    attributeType="css"
                    attributeName="stroke-dasharray"
                    from="0" to="251.2" dur="1s" />
                    </path>
                  </svg>
            <div id="nonSvgBox"
              ref={(square) => { this.square = square; }} 
              ></div>
                </div>
            );
        }
    }
    
    ReactDOM.render(<Component />, document.getElementById('app'));
    

    【讨论】:

      猜你喜欢
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 2016-09-09
      • 2020-06-20
      • 2017-08-30
      相关资源
      最近更新 更多