为啥我的 React 手风琴动画不起作用?

Posted

技术标签:

【中文标题】为啥我的 React 手风琴动画不起作用?【英文标题】:Why won't my React accordion animation work?为什么我的 React 手风琴动画不起作用? 【发布时间】:2018-03-20 20:17:37 【问题描述】:

我在 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

【问题讨论】:

避免为display 属性设置动画。 codepen.io/solbreslin/pen/QqmRLN -- 无法正常工作,但您可以通过删除 display 来查看高度过渡 【参考方案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;
  


试试下面的 sn-p 或查看分叉的 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 渲染内容会让您的生活变得困难。

【讨论】:

非常感谢!我注意到您还按照@ovokuro 的建议从CSS 中删除了display。它会破坏转换吗? 没问题 :) 我很高兴它有帮助。

以上是关于为啥我的 React 手风琴动画不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

Angular-ui-bootstrap 手风琴和折叠动画不起作用

为啥我的左右移动动画不起作用?

为啥我的图像动画代码不起作用?

为啥我的动画在 Firefox 中不起作用?

为啥我的动画在 Roblox Studio 中不起作用

为啥我的链接颜色关键帧动画在 Chrome 中不起作用?