核心实现原理
监听选中事件:通过 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> 网友回复


