Maison > Article > interface Web > Création d'un composant de dialogue de transition fluide dans React (Partie)
Bienvenue dans la première partie de ma série en quatre parties sur la création d'un composant de dialogue réactif dans React. Dans cette série, j'explorerai différentes approches pour obtenir des transitions d'animation fluides tout en conservant les dimensions fluides du dialogue. Dans cette première partie, je vais configurer le composant de dialogue de base avec des fonctionnalités de réduction et d'expansion.
Veuillez noter que l'accessibilité et la conception réactive ne font pas partie des considérations de cette série. L'objectif principal est de créer un composant de dialogue réutilisable avec des transitions d'animation fluides.
Cette série fait partie d'une preuve de concept sur laquelle j'ai travaillé, visant à discuter et à affiner les techniques d'animation des composants de l'interface utilisateur. J'invite les commentaires et les idées de mes collègues développeurs pour valider mon approche ou suggérer des améliorations.
Commençons par créer un composant de dialogue hautement réutilisable qui prend en charge la réduction et l'expansion. J'utiliserai le modèle de composition pour m'assurer que le dialogue peut s'adapter à l'évolution du contenu.
Structure des fichiers :
src/ components/ FluidDialog/ Dialog.js DialogContext.js DialogHeader.js DialogBody.js DialogFooter.js DialogContainer.js index.js App.js index.js
Tout d'abord, je vais créer un contexte pour gérer l'état de notre composant de dialogue.
Points clés :
// 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); }
Ensuite, je vais créer le composant de dialogue principal qui utilise le contexte pour gérer l'expansion et la minimisation.
Points clés :
// 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; `;
Je créerai des composants supplémentaires pour l'en-tête, le corps, le pied de page et le conteneur de la boîte de dialogue afin de garantir la modularité et la réutilisabilité.
Points clés :
// 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; `;
Enfin, je vais importer et utiliser le composant de dialogue dans l'application principale.
Points clés :
// 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') );
Vous pouvez accéder à l'intégralité du code source sur CodeSandbox.
Vous pouvez également voir un aperçu en direct de la mise en œuvre :
Dans cette première partie, j'ai mis en place une boîte de dialogue de base dans React avec des fonctionnalités de réduction et d'expansion. Ce composant fondamental servira de base à d’autres améliorations dans les prochains articles. Le composant de dialogue est conçu pour épouser son contenu et s'adapter aux changements, le rendant hautement réutilisable et flexible.
Restez à l'écoute pour la partie 2, où je vais me plonger dans l'ajout d'animations aux transitions de dialogue, en explorant différentes options pour obtenir des effets fluides.
J'invite les commentaires et commentaires de mes collègues développeurs à m'aider à affiner et à améliorer cette approche. Vos idées sont inestimables pour rendre cette preuve de concept plus robuste et efficace.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!