我试图通过按下右下角的动作按钮来创建一个弹出式模态。我希望模态向上滑动,模态背后的背景模糊。现在,模态只在按钮被按下并再次关闭时出现。这很好,但我希望背景模糊和菜单滑向上平滑。如果可能的话,我想有按钮变成白色时模态是开放的。下面是代码:
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;
模态组件
为了使模态组件平滑地过渡到视图而不是突然出现,两个布尔值是必要的。第一个值是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%的平移偏移量,这将元素置于屏幕底部。
.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;
标题>