前言
在Web应用开发中,右键菜单是一个常见的功能。今天,我要分享一个我开发的跨框架右键菜单插件 context-menu-plugin
,它不仅支持Vue 3和React,还具备了丰富的功能特性和优秀的交互体验。
核心特性
1. 跨框架支持
这个插件最大的特点是同时支持Vue 3和React两大主流框架。通过抽象共享逻辑和样式,实现了框架无关的核心功能,同时又保持了框架特定的最佳实践。
// Vue 3 使用示例
<template>
<div v-context-menu="menuOptions"> 右键点击此区域 </div> </template>
// React 使用示例
const [contextMenu] = useContextMenu();
<div onContextMenu={contextMenu}> 右键点击此区域 </div>
2. 丰富的功能支持
多级子菜单
支持无限层级的子菜单,每个子菜单都继承父菜单的主题和样式。
主题支持
内置四种主题:
-
Light(默认):清爽的白色主题
-
Dark:深色主题
-
Blue:蓝色主题
-
Green:绿色主题
通过CSS变量实现主题切换,方便用户自定义:
:root {
--cm-light-bg: #ffffff;
--cm-light-text: #333333;
--cm-light-hover: #f5f5f5;
--cm-light-border: #e8e8e8;
}
完整的键盘支持
-
↑/↓:导航菜单项
-
→:打开子菜单
-
←:返回上级菜单
-
Enter/Space:选择菜单项
-
Esc:关闭菜单
3. 优秀的交互体验
智能定位
自动检测视口边界,确保菜单始终在可见区域内显示:
// 位置计算逻辑
const position = { x: Math.min(event.clientX, window.innerWidth - menuWidth), y: Math.min(event.clientY, window.innerHeight - menuHeight) };
平滑动画
使用CSS动画提供流畅的过渡效果:
.context-menu {
animation-duration: var(--cm-animation-duration); animation-name: cmFadeIn;
}
@keyframes cmFadeIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); } }
4. 可访问性支持
遵循WCAG准则,确保菜单对所有用户都可用:
<div role="menu" aria-orientation="vertical" aria-label="上下文菜单" > <div role="menuitem" aria-disabled={disabled} tabIndex={0} > 菜单项 </div>
5. 响应式设计
自动适配移动设备:
@media (max-width: 768px) { .context-menu { min-width: 160px; font-size: 16px; // 更大的字体 .cm-item { padding: 10px 16px; // 更大的点击区域 } } }
技术实现亮点
1. Portal/Teleport技术
为了避免菜单被父元素的overflow
或z-index
影响,使用Portal/Teleport将菜单渲染到body层级:
// React版本
return ReactDOM.createPortal( <ContextMenu />, document.body );
// Vue 3版本
<Teleport to="body"> <ContextMenu /> </Teleport>
2. 共享核心逻辑
通过抽象共享代码,确保两个框架版本的行为一致:
src/
├── shared/
│ ├── contextAware.js // 上下文感知逻辑
│ ├── i18n.ts // 国际化支持
│ ├── types.ts // TypeScript类型定义
│ └── utils.js // 通用工具函数
├── react/ // React实现
└── vue3/ // Vue 3实现
3. 性能优化
- 使用防抖处理窗口调整事件
- 使用事件委托处理菜单项点击
- 懒加载子菜单内容
使用方法
安装
Vue 3使用示例
<script setup>
import { useContextMenu } from 'context-menu-plugin/vue3';
const menuOptions = {
items: [
{ label: '新建', icon: '📄',
children: [
{ label: '文件', onClick: () => {} },
{ label: '文件夹', onClick: () => {} } ] },
{ type: 'separator' },
{ label: '刷新', shortcut: 'Ctrl+R', onClick: () => {} } ] };
</script>
<template>
<div v-context-menu="menuOptions"> 右键点击此区域 </div>
</template>
React使用示例
import { useContextMenu } from 'context-menu-plugin/react';
function App() {
const [contextMenu] = useContextMenu({
items: [
{ label: '新建', icon: '📄', children: [ { label: '文件', onClick: () => {} },
{ label: '文件夹', onClick: () => {} } ] },
{ type: 'separator' },
{ label: '刷新', shortcut: 'Ctrl+R', onClick: () => {} } ] });
return ( <div onContextMenu={contextMenu}> 右键点击此区域 </div> );
}
总结
这个右键菜单插件通过跨框架支持、丰富的功能特性、优秀的交互体验和完善的可访问性支持,为Web应用开发提供了一个强大而灵活的解决方案。无论是Vue 3还是React项目,都能轻松集成并提供一致的用户体验。
未来计划
- 添加更多主题预设
- 支持更多自定义选项
- 添加更多动画效果
- 优化移动端体验
- 添加更多辅助功能支持