Heim > Artikel > Web-Frontend > Erstellen einer Dialogkomponente mit sanften Übergängen in React (Teil)
Willkommen zum ersten Teil meiner vierteiligen Serie zum Erstellen einer responsiven Dialogkomponente in React. In dieser Serie werde ich verschiedene Ansätze untersuchen, um reibungslose Animationsübergänge zu erzielen und gleichzeitig die fließenden Dimensionen des Dialogs beizubehalten. In diesem ersten Teil richte ich die grundlegende Dialogkomponente mit Minimierungs- und Erweiterungsfunktionen ein.
Bitte beachten Sie, dass Barrierefreiheit und responsives Design nicht Teil der Überlegungen dieser Serie sind. Das Hauptaugenmerk liegt auf der Erstellung einer wiederverwendbaren Dialogkomponente mit reibungslosen Animationsübergängen.
Diese Serie ist Teil eines Proof of Concept, an dem ich gearbeitet habe und dessen Ziel es ist, Techniken zur Animation von UI-Komponenten zu diskutieren und zu verfeinern. Ich bitte um Feedback und Erkenntnisse von anderen Entwicklern, um meinen Ansatz zu validieren oder Verbesserungen vorzuschlagen.
Beginnen wir mit der Erstellung einer hoch wiederverwendbaren Dialogkomponente, die das Minimieren und Erweitern unterstützt. Ich werde das Kompositionsmuster verwenden, um sicherzustellen, dass sich der Dialog an sich ändernde Inhalte anpassen kann.
Dateistruktur:
src/ components/ FluidDialog/ Dialog.js DialogContext.js DialogHeader.js DialogBody.js DialogFooter.js DialogContainer.js index.js App.js index.js
Zuerst erstelle ich einen Kontext, um den Status unserer Dialogkomponente zu verwalten.
Wichtige Punkte:
// 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); }
Als nächstes erstelle ich die Hauptdialogkomponente, die den Kontext für die Erweiterung und Minimierung verwendet.
Wichtige Punkte:
// 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; `;
Ich erstelle zusätzliche Komponenten für die Dialogkopfzeile, den Textkörper, die Fußzeile und den Container, um Modularität und Wiederverwendbarkeit sicherzustellen.
Wichtige Punkte:
// 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; `;
Zuletzt importiere und verwende ich die Dialogkomponente in der Haupt-App.
Wichtige Punkte:
// 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') );
Sie können auf den gesamten Quellcode auf CodeSandbox zugreifen.
Sie können auch eine Live-Vorschau der Umsetzung sehen:
In diesem ersten Teil habe ich in React ein einfaches Dialogfeld mit Minimierungs- und Erweiterungsfunktionen eingerichtet. Diese grundlegende Komponente wird als Grundlage für weitere Verbesserungen in den kommenden Artikeln dienen. Die Dialogkomponente ist so konzipiert, dass sie sich an den Inhalt anpasst und sich an Änderungen anpasst, wodurch sie äußerst wiederverwendbar und flexibel ist.
Bleiben Sie gespannt auf Teil 2, in dem ich mich mit dem Hinzufügen von Animationen zu den Dialogübergängen befasse und verschiedene Optionen erkunde, um reibungslose Effekte zu erzielen.
Ich bitte um Feedback und Kommentare von anderen Entwicklern, um diesen Ansatz zu verfeinern und zu verbessern. Ihre Erkenntnisse sind von unschätzbarem Wert, um diesen Proof of Concept robuster und effektiver zu machen.
Das obige ist der detaillierte Inhalt vonErstellen einer Dialogkomponente mit sanften Übergängen in React (Teil). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!