Flask拼写检查器实现实时红色波浪线标记错误的方案咨询
解决方案:实现实时拼写错误红色波浪线标记
核心问题分析
原生<textarea>是纯文本输入控件,无法为单个词汇添加样式,这是你之前尝试替换成div但未生效的关键原因——需要用contenteditable属性的div来实现富文本编辑+样式标记,同时要处理光标位置、词汇匹配等细节。
步骤1:替换输入控件为contenteditable div
将原来的textarea替换为可编辑div,基础样式模拟输入框:
<div id="inputText" contenteditable="true" style="border:1px solid #ccc; padding:8px; min-height:100px; white-space: pre-wrap;"></div>
步骤2:修改JavaScript逻辑,实现实时检测与样式标记
整合分词、错误检测逻辑,并添加光标位置恢复、精准词汇匹配功能:
const inputDiv = document.getElementById('inputText'); // 监听空格/回车键触发拼写检查 inputDiv.addEventListener('keydown', function(e) { if (e.key === ' ' || e.key === 'Enter') { setTimeout(checkSpelling, 80); // 延迟确保文本已写入DOM } }); function checkSpelling() { const inputText = inputDiv.innerText; // 合并两次请求(也可后端合并接口减少请求) fetch("/tokenize", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: inputText }), }) .then(response => response.json()) .then(tokenData => { return fetch("/detect_errors", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ tokens: tokenData.tokens }), }); }) .then(response => response.json()) .then(errorData => { const errors = errorData.errors; if (!errors.length) return; // 保存当前光标位置,避免替换后光标跳转到开头 const selection = window.getSelection(); const cursorRange = selection.getRangeAt(0); const cursorOffset = cursorRange.startOffset; const cursorParent = cursorRange.startContainer.parentNode; // 替换错误词汇为带红色波浪线的span let processedHtml = inputDiv.innerText; errors.forEach(errorWord => { // 用正则边界\b确保匹配完整词汇,避免部分匹配 const safeWord = escapeRegExp(errorWord); const regex = new RegExp(`\\b${safeWord}\\b`, 'g'); processedHtml = processedHtml.replace(regex, `<span style="text-decoration: underline red wavy;">${errorWord}</span>`); }); inputDiv.innerHTML = processedHtml; // 恢复光标位置 restoreCursorPosition(cursorParent, cursorOffset); }) .catch(err => console.error("拼写检查出错:", err)); } // 辅助函数:转义正则特殊字符 function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } // 辅助函数:恢复光标位置 function restoreCursorPosition(parentNode, offset) { const selection = window.getSelection(); const newRange = document.createRange(); newRange.setStart(parentNode, offset); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); }
关键细节说明
- contenteditable特性:允许div作为富文本编辑容器,支持插入带样式的HTML元素
- 光标位置保存/恢复:解决替换HTML后光标跳转的问题,提升编辑体验
- 精准词汇匹配:用正则
\b边界确保只匹配完整词汇,避免误标(比如"test"不会匹配"testing") - 实时触发时机:监听空格和回车键,确保用户输入完一个词汇后立即检测
内容的提问来源于stack exchange,提问作者Fufa Wakgari
相关产品推荐
相关产品推荐

