2017-10-09 16 views
3

私は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

'display'プロパティをアニメーション化しないでください。 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; 
    } 
} 

を0

下記のスニペットを試してみてください。または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クラスを使っているように)条件付きクラスのためだけに状態を使うのが最も簡単だと思います。私はCSSアニメーションをやろうとすると、コンテンツをDOMに条件付きでレンダリングするとあなたの人生が困難になると思います。

+0

ありがとうございます! @ovokuroが示唆しているように、CSSから 'display'も削除したことに気付きました。トランジションを壊すだけですか? – renzyq19

+0

問題はありません:)私はそれが助けてうれしいです。 –

関連する問題