首页 web前端 css教程 在 React 中创建平滑过渡的对话框组件(部分)

在 React 中创建平滑过渡的对话框组件(部分)

Jul 18, 2024 am 01:23 AM

Creating a Smooth Transitioning Dialog Component in React (Part )

第 1 部分:设置具有最小化/展开功能的基本对话框组件

欢迎来到我的关于在 React 中创建响应式对话框组件的四部分系列的第一部分。在本系列中,我将探索不同的方法来实现平滑的动画过渡,同时保持对话框的流体尺寸。在最初的部分中,我将设置具有最小化和展开功能的基本对话框组件。

请注意,可访问性和响应式设计不属于本系列考虑因素的一部分。主要重点是创建具有平滑动画过渡的可重用对话框组件。

本系列是我一直致力于的概念验证的一部分,旨在讨论和完善 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 组件使用相关道具初始化上下文提供程序。
  • 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;
`;
登录后复制

第四步:把它们放在一起

最后,我将在主应用程序中导入并使用对话框组件。

要点:

  • App 组件包括 Dialog 及其页眉、正文和页脚组件。
  • 此设置可确保对话框为后续部分中的进一步增强和动画做好准备。
// 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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

使用智能表单框架创建JavaScript联系表格 使用智能表单框架创建JavaScript联系表格 Mar 07, 2025 am 11:33 AM

使用智能表单框架创建JavaScript联系表格

将框阴影添加到WordPress块和元素 将框阴影添加到WordPress块和元素 Mar 09, 2025 pm 12:53 PM

将框阴影添加到WordPress块和元素

创建一个具有可满足属性的内联文本编辑器 创建一个具有可满足属性的内联文本编辑器 Mar 02, 2025 am 09:03 AM

创建一个具有可满足属性的内联文本编辑器

揭开屏幕读取器的神秘面纱:可访问的表格和最佳实践 揭开屏幕读取器的神秘面纱:可访问的表格和最佳实践 Mar 08, 2025 am 09:45 AM

揭开屏幕读取器的神秘面纱:可访问的表格和最佳实践

使用GraphQL缓存 使用GraphQL缓存 Mar 19, 2025 am 09:36 AM

使用GraphQL缓存

使您的第一个自定义苗条过渡 使您的第一个自定义苗条过渡 Mar 15, 2025 am 11:08 AM

使您的第一个自定义苗条过渡

在node.js中使用multer上传并上传express 在node.js中使用multer上传并上传express Mar 02, 2025 am 09:15 AM

在node.js中使用multer上传并上传express

比较5个最佳的PHP形式构建器(和3个免费脚本) 比较5个最佳的PHP形式构建器(和3个免费脚本) Mar 04, 2025 am 10:22 AM

比较5个最佳的PHP形式构建器(和3个免费脚本)

See all articles