【问题标题】:How to use transition effect on accordion如何在手风琴上使用过渡效果
【发布时间】:2020-10-05 18:36:15
【问题描述】:

我使用 React 和样式化组件创建了简单的手风琴。我在制作效果时遇到问题,以便下部可以慢慢滑出而不是立即弹出。我使用了过渡,但我不知道为什么它在我的情况下不起作用。我的代码中有一部分:https://codesandbox.io/s/sweet-blackwell-v78wt?file=/src/App.js

【问题讨论】:

  • 你查看答案了吗?

标签: javascript reactjs accordion styled-components


【解决方案1】:

为了获得最佳效果,您需要将 max-height0px 转换为内容的高度,反之亦然。您需要使用 useRefuseEffect 挂钩来选择元素并手动设置它们的样式。

您还需要一个知道内容高度的内部包装器。这将作为在折叠容器上设置max-height 的参考。

使用onTransitionEnd 事件监听器,您可以在手风琴展开时删除max-height 属性。这使元素能够根据内容响应地调整大小。

内容的高度由getBoundingClientRect() 函数确定。它返回一个具有元素高度、宽度(和更多)的对象。这样你就可以确定内容容器的高度了。

以下示例是基于您的代码的可行示例。

import React, { useState, useRef, useEffect } from "react";
import "./styles.css";
import styled from "styled-components";

const Accordion = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [isAnimating, setIsAnimating] = useState(false);
  const collapseRef = useRef(null);
  const contentRef = useRef(null);

  const handleClick = () => {
    /**
     * isAnimating prevents the accordion from changing
     * state when it is in the middle of a transition.
     */
    if (!isAnimating) {
      setIsAnimating(true);
      setIsExpanded((isExpanded) => !isExpanded);
    }
  };

  const handleTransition = () => {
    if (isExpanded) {
      /**
       * Removing the max-height when expanded makes sure
       * that the element still resizes responsively correct.
       */
      collapseRef.current.style.maxHeight = "";
    }
    setIsAnimating(false);
  };

  useEffect(() => {
    const { height } = contentRef.current.getBoundingClientRect();
    collapseRef.current.style.maxHeight = `${height}px`;
    if (!isExpanded) {
      /**
       * This makes sure that the element first is expanded
       * and in the next frame paint is transitioned to 0px.
       * Otherwise the 0px height would overwrite to dynamic height
       * and there'd be no transition.
       */
      requestAnimationFrame(() => {
        collapseRef.current.style.maxHeight = "0px";
      });
    }
  }, [isExpanded]);

  return (
    <ContentWrapper onClick={handleClick}>
      <TitleCard>
        <h2>Example text</h2>
      </TitleCard>
      <DescriptionCard
        ref={collapseRef}
        isVisible={isExpanded}
        style={{ maxHeight: "0px" }}
        onTransitionEnd={handleTransition}
      >
        <DescriptionContent ref={contentRef}>
          <p>Example text 2</p>
          <p>Now it expands based on the height of the</p>
          <h3>content.</h3>
          <p>Now it expands based on the height of the</p>
          <h3>content.</h3>
        </DescriptionContent>
      </DescriptionCard>
    </ContentWrapper>
  );
};

export default function App() {
  return (
    <div className="App">
      <Accordion />
    </div>
  );
}

const DescriptionContent = styled.div`
  display: flex;
  flex-direction: column;
`;

const DescriptionCard = styled.div`
  background: grey;
  overflow: hidden;
  align-items: center;
  justify-content: flex-start;
  transition: max-height 0.35s;
`;

const TitleCard = styled.div`
  cursor: pointer;
  height: 4.8rem;
  background: #ffffff;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 1.5em;
`;

const ContentWrapper = styled.div`
  border-radius: 16px;
  border: 2px solid black;
  overflow: hidden;
`;

【讨论】:

    猜你喜欢
    • 2012-02-19
    • 1970-01-01
    • 2012-02-20
    • 2022-10-08
    • 1970-01-01
    • 1970-01-01
    • 2015-09-13
    • 2023-03-26
    相关资源
    最近更新 更多