如何修复textarea中特定词汇触发自定义右键菜单及词汇替换功能
修复textarea右键特定词汇菜单与替换功能
需求说明
- 使用JavaScript实现textarea内词汇的追加与替换功能;
- 自定义右键菜单仅在右键点击textarea中属于指定数组
specificwords(包含'hi'、'hello'、'yo'等词汇)的词汇时才触发显示,菜单需包含词汇替换选项;若点击的词汇不在数组中,菜单不显示。
现有问题
当前代码有两个核心问题:
- 逻辑错误:只要textarea里存在特定词汇,右键点击任意位置都会弹出菜单,未判断点击位置是否落在目标词汇上;
- 功能缺失:完全未实现词汇替换功能,无法满足需求。
修复后的完整代码
HTML
<!DOCTYPE html> <head> <link href="./main.css" rel="stylesheet"/> </head> <body> <textarea>hello This is some text. Click on any word and then do right click</textarea> <ul class="custom-context-menu"> <li data-action="replace">替换为 rule</li> <li data-action="replace">替换为 slde</li> <li data-action="replace">替换为 rebaz</li> <li data-action="append">追加到末尾</li> </ul> </body> <script src="./main.js" type="text/javascript"></script> </html>
CSS
.custom-context-menu { z-index: 1100; display: none; position: absolute; list-style: none; margin: 0; padding: 0; border: 1px solid black; background: white; } .custom-context-menu li { padding: 5px; cursor: pointer; } .custom-context-menu li:hover { background-color: aqua; }
JavaScript
const textarea = document.querySelector("textarea"); const contextMenu = document.querySelector(".custom-context-menu"); const specificWords = ['hi', 'hello', 'yo', 'hey', 'some', 'howdy']; let clickedWord = null; // 获取右键点击位置对应的词汇 function getClickedWord(textarea, event) { const start = textarea.selectionStart; const value = textarea.value; // 向左定位单词起始位置 let left = start; while (left > 0 && /\S/.test(value[left - 1])) { left--; } // 向右定位单词结束位置 let right = start; while (right < value.length && /\S/.test(value[right])) { right++; } // 提取单词并去除标点,转小写用于匹配数组 const word = value.slice(left, right).replace(/[^\w]/g, '').toLowerCase(); return { word, left, right }; } textarea.addEventListener('contextmenu', (event) => { event.preventDefault(); const { word, left, right } = getClickedWord(textarea, event); // 仅当点击的词汇在指定数组中时显示菜单 if (specificWords.includes(word)) { clickedWord = { word, left, right }; // 定位菜单到点击坐标 contextMenu.style.left = `${event.pageX}px`; contextMenu.style.top = `${event.pageY}px`; contextMenu.style.display = 'block'; contextMenu.classList.add('on'); } else { // 点击非目标词汇时隐藏菜单 contextMenu.style.display = 'none'; contextMenu.classList.remove('on'); clickedWord = null; } }); // 处理菜单点击事件:替换或追加词汇 contextMenu.addEventListener('click', (event) => { if (!clickedWord) return; const action = event.target.dataset.action; const targetText = event.target.textContent.replace(/替换为 /, ''); if (action === 'replace') { // 替换选中的目标词汇 const newValue = textarea.value.slice(0, clickedWord.left) + targetText + textarea.value.slice(clickedWord.right); textarea.value = newValue; // 光标定位到替换后的词汇末尾 textarea.selectionStart = textarea.selectionEnd = clickedWord.left + targetText.length; } else if (action === 'append') { // 将词汇追加到textarea末尾 textarea.value += ` ${targetText}`; textarea.selectionStart = textarea.selectionEnd = textarea.value.length; } // 操作完成后隐藏菜单 contextMenu.style.display = 'none'; contextMenu.classList.remove('on'); clickedWord = null; }); // 点击页面其他区域时隐藏菜单 document.addEventListener('click', (event) => { if (contextMenu.classList.contains('on') && !contextMenu.contains(event.target)) { contextMenu.style.display = 'none'; contextMenu.classList.remove('on'); clickedWord = null; } });
关键修复说明
- 精准定位点击词汇:新增
getClickedWord函数,利用textarea的selectionStart属性定位点击位置,提取对应词汇并处理标点、大小写后,与指定数组比对,只有匹配才显示菜单; - 实现替换与追加功能:给菜单项添加
data-action标记操作类型,点击时根据记录的词汇位置完成替换,或追加到文本末尾,同时调整光标位置提升体验; - 优化菜单状态管理:点击非目标词汇或页面其他区域时,及时隐藏菜单并重置状态,避免菜单异常残留。
内容的提问来源于stack exchange,提问作者user22886467
相关产品推荐
相关产品推荐

