javascript 从底部打开Modal并模糊背景

vaj7vani  于 2023-04-04  发布在  Java
关注(0)|答案(2)|浏览(101)

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

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;

我需要帮助!非常感谢!

xriantvc

xriantvc1#

为了实现模糊背景和平滑滑动模式的所需功能,您可以使用CSS和React动画。
因此,让我们对您的代码进行一些更改,以便将其存档。

UpcomingEvents组件

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;

中央支助组

.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;
nbysray5

nbysray52#

模态组件

为了使模态组件平滑地过渡到视图中而不是突然出现,需要两个布尔值。第一个值是open prop,它确定组件是否被挂载并触发useEffect更新isVisible状态值。然后使用此状态值添加或删除开放类。
当点击背景时,调用handleClose函数,将isVisible值设置为false,并在转换结束后触发onClose函数。onClose函数负责从外部重置open prop 。

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;

相关问题