核心实现原理
监听选中事件:通过 CodeMirror 的 selectionChange 事件监听文本选中状态。
计算菜单位置:根据选中文本的坐标动态定位悬浮菜单。
渲染自定义菜单:创建 DOM 元素作为悬浮菜单,绑定交互事件。
完整代码
点击查看全文
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>CodeMirror 悬浮菜单</title> <link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/codemirror.css"> <style> /* 悬浮菜单样式 */ .code-menu { position: absolute; background: white; border: 1px solid #ddd; border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); z-index: 100; padding: 4px; display: none; } .code-menu button { display: block; width: 100%; padding: 6px 12px; background: none; border: none; text-align: left; cursor: pointer; } .code-menu button:hover { background: #f0f0f0; } </style> </head> <body> <textarea id="editor">// 选中代码试试看 function hello() { console.log("Hello World"); }</textarea> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/codemirror/codemirror.5.26.js"></script> <script> // 初始化编辑器 const editor = CodeMirror.fromTextArea(document.getElementById('editor'), { lineNumbers: true, mode: 'javascript', value: '// 测试选中这段代码\nfunction test() { console.log("Hello"); }' }); // 创建菜单 const menu = document.createElement('div'); menu.className = 'code-menu'; document.body.appendChild(menu); // 菜单操作项 ['复制', '注释', '格式化'].forEach(text => { const btn = document.createElement('button'); btn.textContent = text; btn.style.display = 'block'; btn.onclick = () => { if (text === '复制') handleCopy(); if (text === '注释') handleComment(); if (text === '格式化') handleFormat(); }; menu.appendChild(btn); }); // 修复事件监听 editor.on('cursorActivity', (cm) => { const selection = cm.getSelection(); selection ? showMenu(cm) : hideMenu(); }); // 优化定位逻辑 function showMenu(cm) { const cursor = cm.getCursor('to'); const coords = cm.cursorCoords(cursor, 'page'); const scroll = cm.getScrollInfo(); menu.style.display = 'block'; menu.style.top = `${coords.top + scroll.top - 15}px`; // 微调垂直位置 menu.style.left = `${coords.right + scroll.left + 10}px`; } function hideMenu() { menu.style.display = 'none'; } // 点击外部关闭 document.addEventListener('click', (e) => { if (!menu.contains(e.target) && !cm.getWrapperElement().contains(e.target)) { hideMenu(); } }); // 示例操作函数 function handleCopy() { const selection = editor.getSelection(); navigator.clipboard.writeText(selection); hideMenu(); } function handleComment() { const selection = editor.getSelection(); editor.replaceSelection(`/* ${selection} */`); } function handleFormat() { const selection = editor.getSelection(); // 此处可调用 Prettier 等格式化工具 alert('格式化功能需集成格式化库'); } </script> </body> </html>
网友回复