2017-10-09 74 views
3

我已經在React中實現了我自己的響應式手風琴,並且我無法讓它在摺疊的開頭處動畫爲什麼我的React手風琴動畫不能使用?

這是特別奇怪的,因爲我可以在標題之前獲得圖標以上下動畫,除了圖標是僞元素之外,我似乎無法看到兩者之間的區別。

JS:

class Accordion extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     active: -1 
    }; 
    } 
    /*** 
    * Selects the given fold, and deselects if it has been clicked again by setting "active to -1" 
    * */ 
    selectFold = foldNum => { 
    const current = this.state.active === foldNum ? -1 : foldNum; 
    this.setState(() => ({ active: current })); 
    }; 

    render() { 
    return (
     <div className="accordion"> 
     {this.props.contents.map((content, i) => { 
      return (
      <Fold 
       key={`${i}-${content.title}`} 
       content={content} 
       handle={() => this.selectFold(i)} 
       active={i === this.state.active} 
      /> 
     ); 
     })} 
     </div> 
    ); 
    } 
} 

class Fold extends React.Component { 
    render() { 
    return (
     <div className="fold"> 
     <button 
      className={`fold_trigger ${this.props.active ? "open" : ""}`} 
      onClick={this.props.handle} 
     > 
      {this.props.content.title} 
     </button> 
      <div 
      key="content" 
      className={`fold_content ${this.props.active ? "open" : ""}`} 
      > 
      {this.props.active ? this.props.content.inner : null} 
      </div> 
     </div> 
    ); 
    } 
} 

CSS:

$line-color: rgba(34, 36, 38, 0.35); 

.accordion { 
    width: 100%; 
    padding: 1rem 2rem; 
    display: flex; 
    flex-direction: column; 
    border-radius: 10%; 
    overflow-y: auto; 
} 

.fold { 
    .fold_trigger { 
    &:before { 
     font-family: FontAwesome; 
     content: "\f107"; 
     display: block; 
     float: left; 
     padding-right: 1rem; 
     transition: transform 400ms; 
     transform-origin: 20%; 
     color: $line-color; 
    } 

    text-align: start; 
    width: 100%; 
    padding: 1rem; 
    border: none; 
    outline: none; 
    background: none; 
    cursor: pointer; 
    border-bottom: 1px solid $line-color; 

    &.open { 
     &:before { 
     transform: rotateZ(-180deg); 
     } 
    } 
    } 

    .fold_content { 
    display: none; 
    max-height: 0; 
    opacity: 0; 
    transition: max-height 400ms linear; 

    &.open { 
     display: block; 
     max-height: 400px; 
     opacity: 1; 
    } 
    } 
    border-bottom: 1px solid $line-color; 
} 

這裏的CodePen:https://codepen.io/renzyq19/pen/bovZKj

+1

避免動畫顯示屬性。 https://codepen.io/solbreslin/pen/QqmRLN - 不能正常工作,但您可以通過移除「display」來看到高度過渡。 – sol

回答

1

如果你想有一個平滑的過渡,我不會有條件地呈現內容。它會使動畫變得特別棘手。


我會改變這樣的:

{this.props.active ? this.props.content.inner : null} 

這樣:

{this.props.content.inner} 

,並使用此scss

.fold_content { 
    max-height: 0; 
    overflow: hidden; 
    transition: max-height 400ms ease; 

    &.open { 
    max-height: 400px; 
    } 
} 

請嘗試下面的代碼或查看分叉CodePen Demo

class Accordion extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     active: -1 
 
    }; 
 
    } 
 
    /*** 
 
    * Selects the given fold, and deselects if it has been clicked again by setting "active to -1" 
 
    * */ 
 
    selectFold = foldNum => { 
 
    const current = this.state.active === foldNum ? -1 : foldNum; 
 
    this.setState(() => ({ active: current })); 
 
    }; 
 

 
    render() { 
 
    return (
 
     <div className="accordion"> 
 
     {this.props.contents.map((content, i) => { 
 
      return (
 
      <Fold 
 
       key={`${i}-${content.title}`} 
 
       content={content} 
 
       handle={() => this.selectFold(i)} 
 
       active={i === this.state.active} 
 
      /> 
 
     ); 
 
     })} 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
class Fold extends React.Component { 
 
    render() { 
 
    return (
 
     <div className="fold"> 
 
     <button 
 
      className={`fold_trigger ${this.props.active ? "open" : ""}`} 
 
      onClick={this.props.handle} 
 
     > 
 
      {this.props.content.title} 
 
     </button> 
 
      <div 
 
      key="content" 
 
      className={`fold_content ${this.props.active ? "open" : ""}`} 
 
      > 
 
      {this.props.content.inner} 
 
      </div> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
const pictures = [ 
 
    "http://unsplash.it/200", 
 
    "http://unsplash.it/200", 
 
    "http://unsplash.it/200", 
 
]; 
 
var test = (title, text, imageURLs) => { 
 
    const images= 
 
    <div className='test-images' > 
 
     {imageURLs.map((url,i) => <img key={i} src={url} />)} 
 
    </div>; 
 

 
    const inner = 
 
    <div className='test-content' > 
 
     <p>{text} </p> 
 
     {images} 
 
    </div>; 
 
    
 
    return {title, inner}; 
 
}; 
 

 
const testData = [ 
 
    test('Title', 'Content',pictures), 
 
    test('Title', 'Content',pictures), 
 
    test('Title', 'Content',pictures), 
 
    test('Title', 'Content',pictures), 
 
    test('Title', 'Content',pictures), 
 
]; 
 

 
ReactDOM.render(<Accordion contents={testData} />, document.getElementById('root'));
.accordion { 
 
    width: 100%; 
 
    padding: 1rem 2rem; 
 
    display: flex; 
 
    flex-direction: column; 
 
    border-radius: 10%; 
 
    overflow-y: auto; 
 
} 
 

 
.fold { 
 
    border-bottom: 1px solid rgba(34, 36, 38, 0.35); 
 
} 
 

 
.fold .fold_trigger { 
 
    text-align: start; 
 
    width: 100%; 
 
    padding: 1rem; 
 
    border: none; 
 
    outline: none; 
 
    background: none; 
 
    cursor: pointer; 
 
    border-bottom: 1px solid rgba(34, 36, 38, 0.35); 
 
} 
 

 
.fold .fold_trigger:before { 
 
    font-family: FontAwesome; 
 
    content: "\f107"; 
 
    display: block; 
 
    float: left; 
 
    padding-right: 1rem; 
 
    transition: transform 400ms; 
 
    transform-origin: 20%; 
 
    color: rgba(34, 36, 38, 0.35); 
 
} 
 

 
.fold .fold_trigger.open:before { 
 
    transform: rotateZ(-180deg); 
 
} 
 

 
.fold .fold_content { 
 
    max-height: 0; 
 
    overflow: hidden; 
 
    transition: max-height 400ms ease; 
 
} 
 

 
.fold .fold_content.open { 
 
    max-height: 400px; 
 
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" /> 
 

 
<div id='root'></div> 
 

 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

注:

我的過渡使用ease代替linear,因爲我認爲這是一個更好的效果。但這只是個人的品味。 linear也可以。

此外,您可以繼續有條件地呈現內容。可以下滑動畫,但不易滑動。有一些你可以探索的transition libraries

但是,我認爲最簡單的方法就是僅僅爲條件類使用狀態(就像您在使用open類一樣)。我認爲有條件地將內容呈現給DOM會讓你的生活變得艱難,如果你想要做CSS動畫。

+0

非常感謝!正如@ovokuro所建議的,我注意到你也從CSS中刪除了'display'。它只是打破轉折? – renzyq19

+0

沒問題:)我很高興它有幫助。 –