从底部打开模式并模糊背景

问题描述 投票:0回答:2

我试图通过按下右下角的操作按钮来创建弹出模式。我希望模态向上滑动,模态后面的背景模糊。现在,当按下按钮并再次关闭时,模式只会出现。这很好,但我希望背景模糊并且菜单可以平滑地向上滑动。如果可能的话,我想让按钮在模态打开时变成白色。这是代码:

import React, { useState } from "react";
import ActionButton from "../../components/ActionButton";
import AddEventActionCard from "../../components/AddEventActionCard";

import AppHeader from "../../components/AppHeader";
import FooterNav from "../../components/FooterNav";
import "../Upcoming_Events/UpcomingEvents.css";

const UpcomingEvents = () => {
  const [click, setClick] = useState(false);
  const handleClick = () => setClick(!click);

  return (
    <div>
      <AppHeader />
      <div className="upcoming-container">
        <div className="upcoming-card-container">
          <div className="upcoming-card-top-header">Upcoming Events</div>
          <div className="upcoming-card-top-events-scroll-container"></div>
        </div>
        {click ? <AddEventActionCard /> : ""}
        <div onClick={handleClick}>
          <ActionButton />
        </div>
      </div>
      <FooterNav />
    </div>
  );
};

export default UpcomingEvents;

我需要一些帮助!非常感谢!

javascript reactjs modal-dialog
2个回答
0
投票

要实现模糊背景和平滑滑动模态的所需功能,您可以使用 CSS 和 React 动画。

因此,让我们对您的代码进行一些更改以将其存档。

即将举行的活动组件

import React, { useState } from "react";
import ActionButton from "../../components/ActionButton";
import AddEventActionCard from "../../components/AddEventActionCard";

import AppHeader from "../../components/AppHeader";
import FooterNav from "../../components/FooterNav";
import "../Upcoming_Events/UpcomingEvents.css";

const UpcomingEvents = () => {
  const [click, setClick] = useState(false);
  const handleClick = () => setClick(!click);

  return (
    <div>
      <AppHeader />
      <div className={`upcoming-container ${click ? "blurred" : ""}`}>
        <div className="upcoming-card-container">
          <div className="upcoming-card-top-header">Upcoming Events</div>
          <div className="upcoming-card-top-events-scroll-container"></div>
        </div>
        <div className={`modal ${click ? "open" : ""}`}>
          {click ? <AddEventActionCard /> : ""}
        </div>
        <div onClick={handleClick}>
          <ActionButton active={click} />
        </div>
      </div>
      <FooterNav />
    </div>
  );
};

export default UpcomingEvents;

CSS

.upcoming-container {
  position: relative;
}

.upcoming-container.blurred {
  filter: blur(5px);
}

.modal {
  position: fixed;
  bottom: -100%;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: white;
  box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.2);
  transition: bottom 0.3s ease-in-out;
}

.modal.open {
  bottom: 0;
}

ActionButton 组件

import React from "react";

const ActionButton = ({ active, onClick }) => {
  return (
    <div
      className={`action-button ${active ? "active" : ""}`}
      onClick={onClick}
    >
      <span className="plus">+</span>
    </div>
  );
};

export default ActionButton;

0
投票

模态组件

为了使模态组件平滑地过渡到视图中而不是突然出现,需要两个布尔值。第一个值是

open
属性,它确定组件是否已挂载并触发 useEffect 更新
isVisible
状态值。然后使用此状态值来添加或删除公开课。

单击背景时,将调用

handleClose
函数,将
isVisible
值设置为 false,并在过渡结束后触发
onClose
函数。
onClose
函数负责从外部重置
open
道具。

import { useState, useEffect, PropsWithChildren, useRef } from 'react';
import ReactDOM from 'react-dom';
import styles from './modal.module.css';

type ModalProps = PropsWithChildren<{
  open: boolean;
  onClose?: () => void;
}>;

const Modal = (props: ModalProps) => {
  const [isVisible, setIsVisible] = useState(false);
  const ref = useRef<HTMLDivElement>(null);
  const { open, onClose, children } = props;
  const className = `${styles.modal} ${isVisible ? styles.open : ''}`.trim();

  const handleClose = () => {
    setIsVisible(false);
    document.body.style.overflow = 'auto';
    ref.current?.addEventListener('transitionend', () => onClose?.());
  };

  useEffect(() => {
    if (open) {
      setIsVisible(true);
      document.body.style.overflow = 'hidden';
    }
  }, [open]);

  return open
    ? ReactDOM.createPortal(
        <>
          <div ref={ref} className={className}>
            <div className={styles.content}>{children}</div>
          </div>
          <div className={styles.backdrop} onClick={handleClose} />
        </>,
        document.getElementById('portal')!
      )
    : null;
};

export default Modal;

CSS 模块

CSS样式表包括四个类:

.modal
.open
.backdrop
.content
.content
类与当前讨论无关,因为它仅涉及模态的内容。

.modal
类负责为父容器提供一个固定位置,具有相对于视口的完整宽度和高度尺寸。此外,它还包括一个 100% 的 translateY 偏移量,它将元素放置在屏幕底部之外。

.open
类用于将
.modal
translateY 属性重置为 0,使元素重新进入视图。

.backdrop
类的不透明度为 0,但包括一个逐渐淡入的过渡。这主要是出于美学目的。
backdrop-filter: blur(0.25rem);
样式属性用于实现所需的模糊效果。

.modal {
  z-index: 9999;
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  transform: translateY(100%);
  transition: transform 0.3s ease-out;
  pointer-events: none !important;
}

.modal.open {
  transform: translateY(0);
}

.backdrop {
  z-index: 9998;
  position: fixed;
  inset: 0;
  background-color: rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease-out;
  backdrop-filter: blur(0.25rem);
}

.modal.open ~ .backdrop {
  opacity: 1;
  pointer-events: auto;
}

.content {
  position: relative;
  z-index: 1;
  color: #333;
  background-color: #fff;
  padding: 2rem;
  border-radius: 0.5rem;
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.3);
  pointer-events: auto;
}

#用法

import React, { useState } from "react";
import ActionButton from "../../components/ActionButton";
import AddEventActionCard from "../../components/AddEventActionCard";
import Modal from "../../components/Modal";

import AppHeader from "../../components/AppHeader";
import FooterNav from "../../components/FooterNav";
import "../Upcoming_Events/UpcomingEvents.css";

const UpcomingEvents = () => {
  const [click, setClick] = useState(false);
  const handleClick = () => setClick(!click);

  return (
    <div>
      <Modal open={click} onClose={() => setClick(false)}>
        <AddEventActionCard />
      </Modal>
      <AppHeader />
      <div className="upcoming-container">
        <div className="upcoming-card-container">
          <div className="upcoming-card-top-header">Upcoming Events</div>
          <div className="upcoming-card-top-events-scroll-container"></div>
        </div>
        <div onClick={handleClick}>
          <ActionButton />
        </div>
      </div>
      <FooterNav />
    </div>
  );
};

export default UpcomingEvents;
© www.soinside.com 2019 - 2024. All rights reserved.