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



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

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;

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

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

所以让我们对你的代码做一些改变来存档。

<<p>UpcomingEvents组件/strong>
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;
}
<<p>ActionButton组件/strong>
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;

模态组件

为了使模态组件平滑地过渡到视图而不是突然出现,两个布尔值是必要的。第一个值是openprop,它决定组件是否被挂载,并触发useEffect更新isVisible状态值。然后使用此状态值来添加或删除开放类。

点击背景时,调用handleClose函数,设置isVisible值为false,并在过渡结束后触发onClose函数。onClose函数负责外部重置openprop。

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%的平移偏移量,这将元素置于屏幕底部。

.open类用于重置.modaltranslateY属性为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;

最新更新