PB06▸🪟 Overlay · 覆蓋層▸選單
Context Menu
右鍵選單
難度 ★★★★★標籤 右鍵 · menu · 位置3 min read
模式簡述
Context Menu:右鍵或長按觸發的選單。檔案管理器、編輯器標配。要處理多種觸發方式、多種位置計算。
右鍵點擊此區域
Claude Code Prompt
參考:PB06 context-menu 組件:ContextMenu.tsx Context Menu:右鍵或長按觸發的選單。檔案管理器、編輯器標配。要處理多種觸發方式、多種位置計算。 限制: - 沒做螢幕邊界判斷 - 手機長按沒實作 - 選單關閉行為不一致
完整程式碼
"use client";
import { useEffect, useState } from "react";
import { Copy, Pencil, Trash2, Share2 } from "lucide-react";
type State = "closed" | "open";
export function ContextMenu({ state = "open" }: { state?: State }) {
const [pos, setPos] = useState<{ x: number; y: number } | null>(
state === "open" ? { x: 80, y: 60 } : null,
);
useEffect(() => {
setPos(state === "open" ? { x: 80, y: 60 } : null);
}, [state]);
return (
<div
onContextMenu={(e) => {
e.preventDefault();
const rect = e.currentTarget.getBoundingClientRect();
setPos({ x: e.clientX - rect.left, y: e.clientY - rect.top });
}}
onClick={() => setPos(null)}
className="relative grid h-[260px] w-full max-w-md place-items-center rounded-lg border border-dashed border-border/60 bg-background/30"
>
<p className="font-mono text-xs text-muted-foreground">
右鍵點擊此區域
</p>
{pos && (
<div
style={{ left: pos.x, top: pos.y }}
className="absolute z-10 w-44 overflow-hidden rounded-md border border-border bg-background py-1 shadow-xl animate-in fade-in zoom-in-95 duration-100"
>
{[
{ icon: Copy, label: "複製", shortcut: "⌘C" },
{ icon: Pencil, label: "重新命名" },
{ icon: Share2, label: "分享" },
].map((it, i) => (
<button
key={i}
className="flex w-full items-center gap-2 px-2.5 py-1.5 text-left text-xs hover:bg-lab-accent/10"
>
<it.icon className="h-3.5 w-3.5" />
<span className="flex-1">{it.label}</span>
{it.shortcut && <kbd className="font-mono text-[10px] text-muted-foreground">{it.shortcut}</kbd>}
</button>
))}
<div className="my-1 border-t border-border" />
<button className="flex w-full items-center gap-2 px-2.5 py-1.5 text-left text-xs text-red-500 hover:bg-red-500/10">
<Trash2 className="h-3.5 w-3.5" />
刪除
</button>
</div>
)}
</div>
);
}何時用
- ✅ 檔案/列表項的次要操作(重新命名、刪除、複製連結)
- ✅ 編輯器上下文相關的快捷操作
- ✅ 需要對單一物件做多種操作
何時別用
- ❌ 手機優先的介面(右鍵概念不存在)
- ❌ 只有兩三個操作(用 dropdown 或 inline 按鈕)
- ❌ 操作會破壞性影響全站(用 modal 確認)
我踩過的坑
-
沒做螢幕邊界判斷:右下角點擊選單超出視口。算位置時要 clamp 到 vw/vh 內。
-
手機長按沒實作:iOS Safari 長按會跳系統選單,要 e.preventDefault()。
-
選單關閉行為不一致:使用者點外面就關,但選了選項也要關,按 ESC 也要關。
相關模式
- PB07
- PE08