返回组件库
抽屉弹层
复刻来源apple.com
React · Vue3弹层反馈ReactVue3遮罩
侧边面板滑入并伴随遮罩淡入,可挂载详情、筛选与设置面板。
业务项目无源码 → 我们复刻实现,自动适配 React,复制代码拿去即可使用。
演示预览实时时长 1x
Workspace / App Window抽屉弹层演示
侧滑抽屉面板ESC
Filter by status...
Select priority...
保存配置取消
播放速度已适配 prefers-reduced-motion
Drawer.jsx
/**
* OmniMotion — 抽屉弹层 / Drawer (React 18+ · 纯 CSS 版本)
* 复刻来源: apple.com — 侧边面板滑入 + 遮罩
* 用法: <Drawer side="right" open onClose={close} />
*/
import { useEffect, useState } from "react";
export default function Drawer({ side = "right", open = false, onClose, children }) {
const [mounted, setMounted] = useState(open);
useEffect(() => {
setMounted(open);
}, [open]);
return (
<div className={"mk-drawer mk-drawer--" + side} data-open={String(open)} aria-hidden={!open}>
<div className="mk-drawer__scrim" onClick={onClose} />
<aside className="mk-drawer__panel" role="dialog" aria-modal="true">
{mounted ? children : null}
</aside>
</div>
);
}
/* 样式(可直接放入全局 CSS)
.mk-drawer { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.mk-drawer[data-open="true"] { pointer-events: auto; }
.mk-drawer__scrim {
position: absolute; inset: 0; background: rgba(0, 0, 0, 0.34);
opacity: 0; transition: opacity 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.mk-drawer[data-open="true"] .mk-drawer__scrim { opacity: 1; }
.mk-drawer__panel {
position: absolute; top: 0; bottom: 0; width: min(420px, 86vw);
padding: 20px; background: var(--mk-card); border-left: 1px solid var(--mk-border);
box-shadow: var(--mk-shadow-float-modal);
transform: translateX(105%);
transition: transform 280ms cubic-bezier(0.3, 0, 0, 1);
}
.mk-drawer--right .mk-drawer__panel { right: 0; }
.mk-drawer--left .mk-drawer__panel { left: 0; border-left: 0; border-right: 1px solid var(--mk-border); transform: translateX(-105%); }
.mk-drawer[data-open="true"] .mk-drawer__panel { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) { .mk-drawer__panel, .mk-drawer__scrim { transition: none } }
*/属性 · Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| side | "left" | "right" | right | 面板滑入方向 |
| open | boolean | false | 是否展开 |
| onClose | () => void | — | 关闭回调(点击遮罩触发) |
<Drawer side="right" open />