【问题标题】:How to set display:block and transition opacity at the same time in React?如何在 React 中同时设置 display:block 和 transition 不透明度?
【发布时间】:2017-11-07 14:21:20
【问题描述】:

我在 JSX 中定义了一个背景层元素,它最初设置了 display:none

<div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />

风格:

const naviBGStyle = {
  display: 'none',
  opacity: 0,
  transition: 'opacity 0.4s ease',
};

单击时,我希望图层使用 css 中定义的过渡平滑消失或重新出现。在render() 中,我检查是否应该显示或隐藏元素:

渲染()

const naviBGStyleClone = Object.assign({}, naviBGStyle);
if (this.props.status === 'closed') {
  naviBGStyleClone.display = 'none';
  naviBGStyleClone.opacity = 0;
} else {
  naviBGStyleClone.display = 'block';
  naviBGStyleClone.opacity = 1;
}

return (
    <div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />
);

现在,这有点像元素将被显示/隐藏,但它会在没有设置不透明度的过渡动画的情况下弹出。

通常我会使用requestAnimationFrame 之类的东西来解决这个问题:

render() with raf:

const naviBGStyleClone = Object.assign({}, naviBGStyle);
if (this.props.status === 'closed') {
  naviBGStyleClone.display = 'none';
  if (typeof window !== 'undefined') {
    window.requestAnimationFrame(() => {
      naviBGStyleClone.opacity = 0;
    });
  }
} else {
  naviBGStyleClone.display = 'block';
  if (typeof window !== 'undefined') {
    window.requestAnimationFrame(() => {
      naviBGStyleClone.opacity = 1;
    });
  }
}

return (
    <div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />
);

但这在 react 中不起作用,因为它会导致样式在 render() 已经完成之后被修改。

那么,在 React 中执行此操作的正确方法是什么?

【问题讨论】:

  • 最常见的方法是通过两个快速步骤完成。将显示设置为阻止,然后在下一个循环中更改不透明度。显示块甚至是一个要求吗?换个 zindex 怎么样?
  • 是的,我认为如果元素使用display:none 从渲染树中完全消失会很好。 “下一个循环”是什么意思?
  • 事件循环的下一个循环。如果您在不显示的元素上触发 css 转换,则不会发生转换。如果你将它设置为阻塞,那么在事件循环的下一轮触发转换就会发生。不管有没有反应,这都是真的。如果你愿意,我可以用一些例子写一个答案。我上面的建议不是唯一的方法
  • @azium 这就是我使用 requestAnimationFrame 的原因 - 不起作用
  • requestAnimationFrame 可以使用,只是不是你拥有它的方式。我会用一些工作示例写一个答案

标签: javascript css reactjs css-transitions jsx


【解决方案1】:

因为通过display: none隐藏的项目不会触发过渡,您可以连续调用setState两次,一次触发显示更改,然后再次触发不透明度更改,反之亦然为了使它淡出然后隐藏。

class App extends React.Component {
  state = { display: 'none', opacity: 0 }

  toggle = () => {
    if (this.state.display === 'none') {
      this.setState({ display: 'block' })
      setTimeout(() =>
        this.setState({ opacity: 1 }), 10 // something very short
      )
    }
    if (this.state.display === 'block') {
      this.setState({ opacity: 0 })
      setTimeout(() =>
        this.setState({ display: 'none' }), 300 // same as transition time
      )
    }
  }

  render() {
    return (
      <div>
        <button onClick={this.toggle}>toggle</button>        
        <div 
          style={{ 
            transition: 'opacity 0.3s ease',
            opacity: this.state.opacity,
            display: this.state.display
          }} 
        />
      </div>
    )
  }
}

Example on codepen

我还鼓励您查看 React Motion 以处理更复杂的转换,就像您可能使用 requestAnimationFrame 所做的那样

https://github.com/chenglou/react-motion

【讨论】:

  • 您为什么使用 setTimeout 而不是 raf?
  • 如果你只调用一次函数没有区别。它们都会在下一个可用的事件循环中触发
  • 是的,我只是问,因为 setTimeout 是不好的做法 afaik
  • 你可能会想到 setInterval,它对动画很不利,因为它没有被可靠地调用。 setTImeout 非常好,特别是如果你在我的代码中调用它一次(不是动画)
猜你喜欢
  • 1970-01-01
  • 2014-09-05
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-01
相关资源
最近更新 更多