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

ren*_*q19 5 javascript css sass css-animations reactjs

我已经在 React 中实现了我自己的响应式手风琴,但我无法让它为 fold 的打开设置动画

这特别奇怪,因为我可以在标题之前获得图标来上下动画,而且除了图标是伪元素之外,我似乎看不出两​​者之间的区别。

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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

这是 CodePen:https ://codepen.io/renzyq19/pen/bovZKj

Dan*_*ger 5

如果您想要平滑过渡,我不会有条件地呈现内容。这将使动画幻灯片特别棘手。


我会改变这个:

{this.props.active ? this.props.content.inner : null}
Run Code Online (Sandbox Code Playgroud)

对此:

{this.props.content.inner}
Run Code Online (Sandbox Code Playgroud)

并使用这个scss

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

  &.open {
    max-height: 400px;
  }
}
Run Code Online (Sandbox Code Playgroud)

试试下面的代码片段或查看分叉的CodePen 演示

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'));
Run Code Online (Sandbox Code Playgroud)
.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

笔记:

我使用ease而不是linear在过渡上,因为我认为这是一个更好的效果。但这只是个人口味。linear也会起作用。

此外,您可以继续有条件地呈现内容。向下滑动动画是可能的,但无法轻松实现向上滑动。您也可以探索一些过渡库

但是,我认为将状态仅用于条件类是最简单的(就像您对open类所做的那样)。我认为如果您尝试制作 CSS 动画,有条件地将内容渲染到 DOM 会使您的生活变得困难。