我试图通过按下右下角的操作按钮来创建弹出模式。我希望模态向上滑动,模态后面的背景模糊。现在,当按下按钮并再次关闭时,模式只会出现。这很好,但我希望背景模糊并且菜单可以平滑地向上滑动。如果可能的话,我想让按钮在模态打开时变成白色。这是代码:
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 动画。
因此,让我们对您的代码进行一些更改以将其存档。
即将举行的活动组件
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;
为了使模态组件平滑地过渡到视图中而不是突然出现,需要两个布尔值。第一个值是
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样式表包括四个类:
.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;