返回组件库

抽屉弹层

复刻来源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面板滑入方向
openbooleanfalse是否展开
onClose() => void—关闭回调(点击遮罩触发)
<Drawer side="right" open />