ホームページ  >  記事  >  ウェブフロントエンド  >  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: すべてをまとめる

最後に、ダイアログ コンポーネントをメイン アプリにインポートして使用します。

キーポイント:

  • App コンポーネントには、ダイアログとそのヘッダー、本文、フッター コンポーネントが含まれています。
  • この設定により、ダイアログは今後のパートでのさらなる機能強化とアニメーションに対応できるようになります。
// 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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。