아래로 반응 슬라이더(동적 높이)

우리는 React "down slider"구성요소를 생성할 것입니다. 버튼을 클릭하면 슬라이드 내용이 아래/위로 미끄러지면서(전체 또는 부분적으로) 나타나거나 사라집니다. 슬라이더는 우리가 지정한 트리거를 사용하여 콘텐츠 높이에 맞게 조정됩니다. 슬라이더 콘텐츠 내부 또는 외부에 버튼을 배치할 수 있습니다.



React, typescript, styled-components를 사용할 것입니다.
vite를 사용하여 앱을 만들었습니다.

먼저 DownSlider.tsx에 새 구성 요소를 만듭니다.

import React from "react";
import styled from "styled-components";

type DownSliderProps = {
  expanded: boolean;
  collapsedHeight: number;
  expandedHeight: number;
};

// height doesn't animate, but max-height does
const Container = styled.div<DownSliderProps>`
  position: relative;
  background-color: beige;
  overflow: hidden; // hide any overflowing content

  ${({ expanded, collapsedHeight, expandedHeight }) =>
    expanded
      ? `max-height: ${expandedHeight}px; transition: max-height 0.5s;`
      : `max-height: ${collapsedHeight}px; transition: max-height 0.5s;`}
`;

// ------------------------------------
// You can place the button inside or outside the content.
type Props = {
  expanded: boolean;
  collapsedHeight: number; // height of the button, if inside content
  expandedHeight: number; // height of expanded content
  children: React.ReactNode;
};

// ------------------------------------
const DownSlider = ({
  expanded,
  collapsedHeight,
  expandedHeight,
  children,
}: Props) => {
  return (
    <Container
      expanded={expanded}
      collapsedHeight={collapsedHeight}
      expandedHeight={expandedHeight}
    >
      {children}
    </Container>
  );
};

export default DownSlider;


그런 다음 TestPage.tsx에서 슬라이더, 버튼, 일부 콘텐츠를 추가하고 일부 지연된 데이터 액세스를 시뮬레이션합니다.

import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";

import { DownSliderButton, DownSlider, Page } from "components";

const DownSliderContainer = styled.div`
  width: 700px;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid forestgreen;
`;

const SlideTitle = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #eee;
  font-weight: bold;
`;

const SlideContent = styled.div`
  padding: 10px;
`;

// ------------------------------------
const TestPage = () => {
  const ref: any = useRef(null); // to measure content height

  const initialHeight = 0; // 0: slides at start, ~1000: no sliding

  const [updatedHeight, setUpdatedHeight] = useState(initialHeight);
  const [isExpanded, setExpanded] = useState(true);
  const [delayedData, setDelayedData] = useState("");

  useEffect(() => {
    setUpdatedHeight(ref.current?.clientHeight);
  }, [ref.current?.clientHeight, delayedData]); // update triggers

  useEffect(() => {
    setTimeout(() => {
      setDelayedData("This data arrives ~2s later.");
    }, 2000);
  }, []);

  // ------------------------------------
  return (
    ...
      <DownSliderContainer>
        <SlideTitle>
          <div>Slide title</div>
          <DownSliderButton isExpanded={isExpanded} setExpanded={setExpanded} />
        </SlideTitle>

        <DownSlider
          expanded={isExpanded}
          collapsedHeight={0}
          expandedHeight={updatedHeight}
        >
          <SlideContent ref={ref}>
            <div>Slide content</div>

            <div>
              <img
                src={"/src/assets/cairn-terrier.jpg"}
                alt="dog"
                height={454}
              />
            </div>

            <div>More data arriving soon.</div>

            <div>{delayedData}</div>
          </SlideContent>
        </DownSlider>
      </DownSliderContainer>
    ...
  );
};

export default TestPage;


완전성을 위해 다음은 DownSliderButton.tsx입니다.

import React from "react";
import styled from "styled-components";

// @ts-ignore
import { Rotator } from "components";
// @ts-ignore
import { CircleArrowRightIcon } from "svg";

const Container = styled.div`
  cursor: pointer;
  color: var(--color-primary-lighter);

  & > div {
    width: 32px;
    height: 32px;
  }
`;

// ------------------------------------
type Props = {
  isExpanded: boolean;
  setExpanded: (isExpanded: boolean) => void;
};

// ------------------------------------
const DownSliderButton = ({ isExpanded, setExpanded }: Props) => {
  return (
    <Container role="button" onClick={() => setExpanded(!isExpanded)}>
      <Rotator rotated={isExpanded ? 90 : 180}>
        <CircleArrowRightIcon />
      </Rotator>
    </Container>
  );
};

export default DownSliderButton;


그리고 로테이터는 그 안에 배치한 모든 것을 회전시킵니다.

import styled, { css } from "styled-components";

type Props = {
  rotated?: number;
};

const Rotator = styled.div<Props>`
  transform: rotate(0deg);
  transition: transform 0.5s ease-out;

  ${({ rotated }) =>
    rotated !== undefined &&
    css`
      transform: rotate(${rotated}deg);
      transition: transform 0.5s ease-out;
    `};
`;

export default Rotator;


내 "svg/index.js"파일 내에서 이 버튼 구성 요소를 선언합니다.

export { ReactComponent as CircleArrowRightIcon } from "svg/circle-arrow-right.svg";


.. 이 svg를 가져옵니다.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentcolor">
  <path d="M256 0C114.6 0 0 114.6 0 256c0 141.4 114.6 256 256 256s256-114.6 256-256C512 114.6 397.4 0 256 0zM406.6 278.6l-103.1 103.1c-12.5 12.5-32.75 12.5-45.25 0s-12.5-32.75 0-45.25L306.8 288H128C110.3 288 96 273.7 96 256s14.31-32 32-32h178.8l-49.38-49.38c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l103.1 103.1C414.6 241.3 416 251.1 416 256C416 260.9 414.6 270.7 406.6 278.6z"/>
</svg>


질문/의견, 알려주세요.

좋은 웹페이지 즐겨찾기