2017-06-06 35 views
0

我在JSX定義的背景層元件,其具有設置display:none intially:如何設置顯示:在React中同時阻止和轉換不透明度?

<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} /> 
); 

現在,這還挺工程作爲元素將顯示/隱藏地,但它沒有過渡動畫啪啪設置不透明度。

通常我會再使用類似​​來解決此像這樣:

渲染()與英國皇家空軍:

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} /> 
); 

但這不會工作,作出反應,它會導致在render()之後要修改的樣式已經完成。

那麼,在React中做到這一點的正確方法是什麼?

+0

最常見的方式做到這一點做的是做它在兩個快速的步驟。將顯示設置爲阻擋,然後在下一個循環中更改不透明度。顯示塊甚至是一個需求?那麼改變zindex呢? – azium

+0

是的,我認爲如果元素使用'display:none'從渲染樹中完全消失將會很好。 「下一個循環」是什麼意思? – Timo

+0

事件循環的下一個循環。如果你在一個顯示爲none的元素上觸發一個css轉換,那麼轉換不會發生。如果將它設置爲阻塞,那麼在事件循環的下一輪觸發轉換,則會發生。無論有沒有反應,情況都是如此。如果你願意,我可以用一些例子寫一個答案。我的以上建議不是唯一的方法 – azium

回答

0

由於過渡不會觸發通過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

我也會鼓勵你看看陣營運動處理更復雜的轉換像你可能會​​

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

+0

任何你使用setTimeout而不是raf的原因? – Timo

+0

如果您只調用一次函數,則沒有區別。他們都會在下一個可用的事件循環中觸發 – azium

+0

是的,我只是在問,因爲setTimeout是不好的練習afaik – Timo