JS文本着色脚本无法自动触发,仅空格键生效问题求助
解决JavaScript文本着色仅空格键触发及页面加载自动着色问题
你的问题出在三个核心点:
- 着色逻辑被绑定在仅空格键触发的
keyup事件判断里,其他按键自然不会触发着色 - 页面加载时没有主动执行着色代码,只有触发指定按键才会运行逻辑
contenteditable元素的onchange事件触发条件极为苛刻,基本无法用于实时内容变化监听
下面是修改后的完整代码,同时解决了所有问题:
修改后的index.html
<div id="editor" contenteditable="true"><h1>This is a Heading</h1> <p>This is a paragraph.</p> </div> <h3>PREVIEW</h3> <div class="preview-area"> <iframe id="preview-window"></iframe> </div>
说明:移除了内联的oninput/onchange属性,改用JS统一绑定事件,代码结构更清晰
修改后的style.css
#editor { width: 400px; height: 100px; padding: 10px; background-color: #444; color: white; font-size: 14px; font-family: monospace; white-space: pre; } .statement { color: orange; } .other { color: white; /* 明确设置默认文本颜色,避免修改HTML后出现继承问题 */ }
修改后的javascript.js
const editor = document.querySelector("#editor"); // 移除重复关键词,不影响匹配结果 const keywords = ["DIV", "H1", "P", "HELLO", "<", ">", "/"]; // 核心着色逻辑抽离为独立函数 function highlightKeywords() { const str = editor.innerText; // 拆分文本为关键词与非关键词片段 const chunks = str.split(new RegExp(keywords.map(w => `(${w})`).join("|"), "i")).filter(Boolean); // 生成带着色标记的HTML const markup = chunks.reduce((acc, chunk) => { acc += keywords.includes(chunk.toUpperCase()) ? `<span class="statement">${chunk}</span>` : `<span class='other'>${chunk}</span>`; return acc; }, ""); // 保存当前光标位置,避免修改HTML后光标错位 const cursorPos = getCursorPosition(editor); // 更新编辑器HTML editor.innerHTML = markup; // 恢复光标到原来的位置 restoreCursorPosition(editor, cursorPos); } // 获取contenteditable元素的光标位置 function getCursorPosition(element) { let pos = 0; const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const preCaretRange = range.cloneRange(); preCaretRange.selectNodeContents(element); preCaretRange.setEnd(range.endContainer, range.endOffset); pos = preCaretRange.toString().length; } return pos; } // 恢复光标到指定位置 function restoreCursorPosition(element, pos) { const selection = window.getSelection(); const range = document.createRange(); range.setStart(element, 0); range.collapse(true); const nodeStack = [element]; let currentNode = null; let charCount = 0; let found = false; while (nodeStack.length > 0 && !found) { currentNode = nodeStack.pop(); if (currentNode.nodeType === Node.TEXT_NODE) { const textLength = currentNode.length; if (charCount + textLength >= pos) { range.setStart(currentNode, pos - charCount); found = true; } else { charCount += textLength; } } else { for (let i = currentNode.childNodes.length - 1; i >= 0; i--) { nodeStack.push(currentNode.childNodes[i]); } } } selection.removeAllRanges(); selection.addRange(range); editor.focus(); } // 预览功能保持不变 function showPreview() { const editorContent = editor.innerText; const frame = document.getElementById("preview-window").contentWindow.document; document.getElementById("preview-window").srcdoc = editorContent; frame.open(); frame.write(editorContent); frame.close(); } // 页面加载完成后自动初始化 document.addEventListener('DOMContentLoaded', () => { highlightKeywords(); // 打开页面立刻着色默认文本 showPreview(); // 初始化预览内容 // 绑定input事件,覆盖所有内容变化场景(输入、删除、粘贴等) editor.addEventListener('input', () => { highlightKeywords(); showPreview(); }); });
关键修改说明
- 抽离核心着色函数:把原来嵌套在
keyup事件里的逻辑单独封装,方便页面加载时调用,也利于后续维护 - 替换
keyup为input事件:input事件能覆盖所有内容变化场景,比仅监听空格键的keyup更可靠 - 页面自动初始化:通过
DOMContentLoaded事件,页面加载完成后立刻执行着色和预览,打开页面就看到效果 - 修复光标定位问题:修改
innerHTML会重置光标位置,新增的光标保存/恢复函数保证编辑体验流畅 - 清理冗余代码:移除重复关键词,删除无用的内联事件,代码更简洁高效
内容的提问来源于stack exchange,提问作者Nodigap
相关产品推荐
相关产品推荐

