切换div动画的自动高度

时间:2019-02-19 14:34:32

标签: css reactjs animation

当我关闭div并且div应该变小时,此代码很好用,但是当我尝试打开div时动画不起作用。为什么会这样,我该怎么做呢?

const Container = styled.div`
  margin: 5px;
  padding: 10px;
  width: 200px;
  max-height: ${props => (props.open ? '500px' : '20px')};
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
  transition: max-height 1s cubic-bezier(0, 1, 0.5, 1);
  background-color: #f6f6f6;
  cursor: pointer;
`;

我希望具有自动高度,但是我读到您可以将max-height设置为比您期望的div更大的高度。缺点是当动画时间为1s时,即使高度小于最大高度,动画也将使用1s来设置最大高度的动画。

2 个答案:

答案 0 :(得分:0)

let isActive = true;

document.getElementById("toggle").addEventListener("click", function(e) {
    document.getElementById("cont").style.height = isActive ? document.getElementById("cont").scrollHeight + "px" : 0;
    isActive = !isActive;
});
.container  {
    width: 100%;
    padding: 0;
    height: 0;
    transition: 1s;
    overflow: hidden;
}

.container-text {
    padding: 10px;
    background: green;
}
<button id="toggle">Toggle</button>
    <div class="container" id="cont">
        <div class="container-text">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere culpa aliquid neque atque aliquam dolorem molestiae ad, optio laborum, vitae aperiam vel explicabo distinctio similique id, eos reprehenderit inventore repudiandae!
        </div>
    </div>

答案 1 :(得分:0)

抱歉,height='auto'上的动画非常“无聊”:P因此,如果您希望Toggle书写始终可见,建议您查看已经存在的Component,例如→https://springload.github.io/react-accessible-accordion/

它们很多,您可以使用诸如react togglereact accordionreact slidedown(或这些的组合:)之类的关键字找到它们

相反,如果您希望在长文本出现时隐藏Toggle书写,那么我为您编写了一个Component(您可以改进它的更多想法,但我认为它已满足您的要求)→{{3} }

这个想法很简单,可以在以下算法中看到:

  1. Toggle组件是通过将isOpen属性设置为true来构造的,因此将呈现长文本。

  2. componentDidMount中,将长文本所需的高度保存在状态属性fullOpenHeight中,并且isOpen属性设置为false

  3. componentDidMount起更新状态以来,Toggle已用短文本呈现,并且已调用componentDidUpdate。这样,自checkInitialHeights起,我们在Component的状态下保存带有短文本的Component的高度,并将te的checkInitialHeights属性设置为false

  4. 再次重新渲染了该组件,现在可以使用它了。请注意,如果您在切换开关完全关闭/完全打开之前再次单击它,我也会使用closeHeightopenHeight属性获得不错的反馈。

希望有帮助!这里也是小提琴。

const animation = (isOpen, closeHeight, openHeight, fullCloseHeight, fullOpenHeight) => {
  if (isOpen && closeHeight !== null && openHeight !== null) {
    return `${slideDown(closeHeight, fullOpenHeight)} 1s linear`;
  }

  if (!isOpen && closeHeight !== null && openHeight !== null) {
    return `${slideUp(fullCloseHeight, openHeight)} 1s linear`;
  }

  return "";
}

const slideDown = (closeHeight, openHeight) => styled.keyframes `
    0% { height: ${closeHeight}px }
    0.1% { height: ${closeHeight}px }
    100% { height: ${openHeight}px }
`;

const slideUp = (closeHeight, openHeight) => styled.keyframes `
    0% { height: ${openHeight}px }
    0.1% { height: ${openHeight}px }
    100% { height: ${closeHeight}px }
`;

const Container = styled.default.div `
    margin: 5px;
    padding: 10px;
    width: 200px;
    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
    background-color: #f6f6f6;
    cursor: pointer;
    box-sizing: border-box;
    animation : ${props => animation(props.toggleState.isOpen, props.toggleState.closeHeight, props.toggleState.openHeight, props.toggleState.fullCloseHeight, props.toggleState.fullOpenHeight)}
    overflow: hidden;
`;

class Toggle extends React.Component {
  toggleDOM;

  constructor(props) {
    super(props);

    this.state = {
      isOpen: true,
      checkInitialHeights: true,
      closeHeight: null,
      openHeight: null,
      fullCloseHeight: null,
      fullOpenHeight: null
    };
    this.toggleDOM = React.createRef();
  }

  handleToggle = (e) => {
    const {
      isOpen
    } = this.state;
    const currHeight = this.toggleDOM.current.getBoundingClientRect().height;

    if (!isOpen) {
      this.setState({
        isOpen: true,
        closeHeight: currHeight
      });
    } else {
      this.setState({
        isOpen: false,
        openHeight: currHeight
      });
    }
  }

  componentDidMount() {
    const toggleDOM = this.toggleDOM.current;
    const fullOpenHeight = toggleDOM.getBoundingClientRect().height;
    this.setState({
      fullOpenHeight,
      isOpen: false
    });
  }

  componentDidUpdate() {
    const toggleDOM = this.toggleDOM.current;
    const {
      isOpen,
      closeHeight,
      openHeight,
      checkInitialHeights
    } = this.state;

    if (checkInitialHeights) {
      const fullCloseHeight = toggleDOM.getBoundingClientRect().height;
      this.setState({
        fullCloseHeight,
        checkInitialHeights: false
      });
      return;
    }

    if (isOpen && openHeight === null) {
      const newOpenHeight = this.toggleDOM.current.getBoundingClientRect().height;
      this.setState({
        openHeight: newOpenHeight
      });
    }
  }

  render() {
    return ( <
      Container innerRef = {
        this.toggleDOM
      }
      onClick = {
        this.handleToggle
      }
      toggleState = {
        this.state
      } > {
        this.state.isOpen ?
        this.props.children :
          this.props.title
      } <
      /Container>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      isToggleOpen: false
    };
  }

  handleToggle = (e) => {
    this.setState(prevState => ({
      isToggleOpen: !prevState.isToggleOpen
    }));
  }

  render() {
    return ( <
      Toggle title = "Spoiler" >
      <
      p >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      Lorem Ipsum < br / >
      <
      /p> <
      /Toggle>
    );
  }
}

ReactDOM.render( < App / > , document.getElementById("root"));
@import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
  font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.2/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/styled-components/3.4.10/styled-components.min.js"></script>

<div id="root"></div>