>  기사  >  웹 프론트엔드  >  React에서 부드러운 전환 대화 상자 구성 요소 만들기(부분)

React에서 부드러운 전환 대화 상자 구성 요소 만들기(부분)

WBOY
WBOY원래의
2024-07-18 01:23:391044검색

Creating a Smooth Transitioning Dialog Component in React (Part )

1부: 최소화/확장 기능을 사용하여 기본 대화 상자 구성 요소 설정

React에서 반응형 대화 상자 구성 요소를 만드는 방법에 관한 4부작 시리즈 중 첫 번째 부분에 오신 것을 환영합니다. 이 시리즈에서는 대화 상자의 유동적 크기를 유지하면서 부드러운 애니메이션 전환을 달성하기 위한 다양한 접근 방식을 살펴보겠습니다. 이번 초기 부분에서는 최소화 및 확장 기능을 갖춘 기본 대화 상자 구성 요소를 설정하겠습니다.

접근성 및 반응형 디자인은 이 시리즈의 고려 사항에 포함되지 않습니다. 주요 초점은 부드러운 애니메이션 전환으로 재사용 가능한 대화 상자 구성 요소를 만드는 것입니다.

이 시리즈는 UI 구성 요소 애니메이션 기술을 논의하고 개선하는 것을 목표로 제가 작업해 온 개념 증명의 일부입니다. 내 접근 방식을 검증하거나 개선 사항을 제안하기 위해 동료 개발자의 피드백과 통찰력을 요청합니다.

기본 대화 상자 구성 요소 설정

최소화 및 확장을 지원하는 재사용 가능성이 높은 대화 상자 구성 요소를 만드는 것부터 시작해 보겠습니다. 대화가 변화하는 콘텐츠에 적응할 수 있도록 구성 패턴을 사용하겠습니다.

파일 구조:

src/
  components/
    FluidDialog/
      Dialog.js
      DialogContext.js
      DialogHeader.js
      DialogBody.js
      DialogFooter.js
      DialogContainer.js
      index.js
  App.js
  index.js

1단계: 대화 컨텍스트

먼저 대화 상자 구성 요소의 상태를 관리하기 위한 컨텍스트를 생성하겠습니다.

핵심 사항:

  • DialogContext는 상태를 유지하고 최소화된 상태와 확장된 상태 사이에서 대화 상자를 전환하는 기능을 제공합니다.
  • DialogProvider 구성 요소는 상태를 초기화하고 이를 컨텍스트를 통해 대화 상자 구성 요소에 제공합니다.
// src/components/FluidDialog/DialogContext.js
import { createContext, useContext, useId, useState } from 'react';

const DialogContext = createContext();

export function DialogProvider({
  rootRef,
  isExpandedByDefault,
  children,
  maxWidth,
}) {
  const dialogId = useId();
  const [isExpanded, setIsExpanded] = useState(isExpandedByDefault);

  return (
    <DialogContext.Provider
      value={{ dialogId, rootRef, isExpanded, setIsExpanded, maxWidth }}
    >
      {children}
    </DialogContext.Provider>
  );
}

export function useDialog() {
  return useContext(DialogContext);
}

2단계: 대화 상자 구성 요소

다음으로 컨텍스트를 사용하여 확장 및 최소화를 처리하는 기본 대화 상자 구성 요소를 생성하겠습니다.

핵심 사항:

  • Dialog 구성 요소는 관련 props로 컨텍스트 제공자를 초기화합니다.
  • DialogComponent 스타일 구성 요소는 대화 상자의 기본 스타일과 레이아웃을 처리합니다.
// src/components/FluidDialog/Dialog.js
import { useRef } from 'react';
import { styled } from 'styled-components';
import { DialogProvider } from './DialogContext';

export default function Dialog({
  id,
  isExpandedByDefault = true,
  maxWidth = 400,
  children,
}) {
  const rootRef = useRef(null);
  return (
    <DialogProvider
      dialogId={id}
      rootRef={rootRef}
      isExpandedByDefault={isExpandedByDefault}
    >
      <DialogComponent
        role="dialog"
        aria-labelledby={`${id}_label`}
        aria-describedby={`${id}_desc`}
        ref={rootRef}
        maxWidth={maxWidth}
      >
        {children}
      </DialogComponent>
    </DialogProvider>
  );
}

const DialogComponent = styled.section`
  max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}px` : undefined)};
  position: absolute;
  right: 16px;
  bottom: 16px;
  border: 1px solid #ccc;
  border-radius: 6px;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.35);
  overflow: hidden;
`;

3단계: 추가 구성 요소

모듈화와 재사용성을 보장하기 위해 대화 상자 머리글, 본문, 바닥글, 컨테이너에 대한 추가 구성 요소를 만들겠습니다.

핵심 사항:

  • DialogHeader에는 컨텍스트를 사용하여 최소화된 상태와 확장된 상태 사이를 전환하는 버튼이 포함되어 있습니다.
  • DialogContainer는 isExpanded 값이 변경되면 본문과 바닥글 콘텐츠를 자동으로 숨기도록 래핑합니다.
  • DialogBody 및 DialogFooter 구성 요소는 대화 상자 콘텐츠에 대한 간단한 컨테이너입니다.
// src/components/FluidDialog/DialogHeader.js
import { styled } from 'styled-components';
import { IconButton } from '../IconButton';
import { useDialog } from './DialogContext';

export default function DialogHeader({ children, expandedTitle }) {
  const { dialogId, isExpanded, setIsExpanded } = useDialog();

  return (
    <DialogHeaderComponent id={`${dialogId}_label`}>
      <ExpandedState isVisible={isExpanded}>
        <Title>{expandedTitle ?? children}</Title>
        <IconButtons>
          <IconButton
            icon="chevron-down"
            onClick={() => setIsExpanded(false)}
          />
        </IconButtons>
      </ExpandedState>
      <MinimizedState
        isVisible={!isExpanded}
        onClick={() => setIsExpanded(true)}
      >
        <Title>{children}</Title>
        <IconButtons>
          <IconButton icon="chevron-up" />
        </IconButtons>
      </MinimizedState>
    </DialogHeaderComponent>
  );
}

const DialogHeaderComponent = styled.div``;

const ExpandedState = styled.header`
  transition: opacity 0.3s;
  opacity: ${({ isVisible }) => (isVisible ? 1 : 0)};
  pointer-events: ${({ isVisible }) => (isVisible ? 'all' : 'none')};
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  background: #f3f3f3;
  display: flex;
  flex-direction: row;
`;

const MinimizedState = styled.header`
  transition: opacity 0.3s;
  opacity: ${({ isVisible }) => (isVisible ? 1 : 0)};
  pointer-events: ${({ isVisible }) => (isVisible ? 'all' : 'none')};
  background: #f3f3f3;
  display: flex;
  flex-direction: row;
  cursor: pointer;
`;

const Title = styled.span`
  flex-grow: 1;
  text-align: left;
  display: flex;
  align-items: center;
  padding: 0 16px;
`;

const IconButtons = styled.div``;
// src/components/FluidDialog/DialogContainer.js
import { styled } from 'styled-components';
import { useDialog } from './DialogContext';

export default function DialogContainer({ children }) {
  const { isExpanded } = useDialog();

  return (
    <DialogContainerComponent isVisible={isExpanded}>
      {children}
    </DialogContainerComponent>
  );
}

const DialogContainerComponent = styled.div`
  display: ${({ isVisible }) => (isVisible ? undefined : 'none')};
`;
// src/components/FluidDialog/DialogBody.js
import { styled } from 'styled-components';
import DialogContainer from './DialogContainer';
import { useDialog } from './DialogContext';

export default function DialogBody({ children }) {
  const { dialogId } = useDialog();

  return (
    <DialogBodyComponent>
      <DialogContainer>
        <DialogBodyContent id={`${dialogId}_desc`}>
          {children}
        </DialogBodyContent>
      </DialogContainer>
    </DialogBodyComponent>
  );
}

const DialogBodyComponent = styled.div``;

const DialogBodyContent = styled.div`
  padding: 8px 16px;
`;
// src/components/FluidDialog/DialogFooter.js
import { styled } from 'styled-components';
import DialogContainer from './DialogContainer';

export default function DialogFooter({ children }) {
  return (
    <DialogFooterComponent>
      <DialogContainer>
        <DialogFooterContent>{children}</DialogFooterContent>
      </DialogContainer>
    </DialogFooterComponent>
  );
}

const DialogFooterComponent = styled.div`
  background: #f3f3f3;
`;

const DialogFooterContent = styled.div`
  padding: 8px 16px;
`;

4단계: 모든 것을 하나로 합치기

마지막으로 메인 앱에서 대화상자 구성요소를 가져와서 사용하겠습니다.

핵심 사항:

  • 앱 구성 요소에는 머리글, 본문, 바닥글 구성 요소가 있는 대화 상자가 포함되어 있습니다.
  • 이 설정을 통해 대화는 향후 부분의 추가 개선 및 애니메이션에 대비할 수 있습니다.
// src/App.js
import React from 'react';
import Dialog from './components/FluidDialog/Dialog';
import DialogHeader from './components/FluidDialog/DialogHeader';
import DialogBody from './components/FluidDialog/DialogBody';
import DialogFooter from './components/FluidDialog/DialogFooter';

function App() {
  return (
    <div className="App">
      <Dialog>
        <DialogHeader>My dialog/DialogHeader>
        <DialogBody>This is the content of the dialog.</DialogBody>
        <DialogFooter>This is the footer of the dialog.</DialogFooter>
      </Dialog>
    </div>
  );
}

export default App;
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

CodeSandbox에서 전체 소스코드에 접근하실 수 있습니다.

또한 구현의 실시간 미리보기를 볼 수도 있습니다.

결론

첫 번째 부분에서는 최소화 및 확장 기능을 갖춘 React의 기본 대화 상자를 설정했습니다. 이 기본 구성 요소는 앞으로 나올 기사에서 추가 개선을 위한 기반이 될 것입니다. 대화 상자 구성 요소는 콘텐츠를 수용하고 변경 사항에 적응하도록 설계되어 재사용성과 유연성이 뛰어납니다.

2부에서는 대화 전환에 애니메이션을 추가하는 방법을 알아보고 부드러운 효과를 얻을 수 있는 다양한 옵션을 살펴보겠습니다.

이 접근 방식을 개선하고 개선하는 데 도움이 되도록 동료 개발자의 피드백과 의견을 요청합니다. 이러한 개념 증명을 더욱 강력하고 효과적으로 만드는 데 귀하의 통찰력은 매우 중요합니다.

위 내용은 React에서 부드러운 전환 대화 상자 구성 요소 만들기(부분)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:프론트엔드 기술다음 기사:프론트엔드 기술