You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用contenteditable的div实现代码高亮与预览功能问题

解决contenteditable编辑器的源码显示与预览问题

问题核心

  • 使用textarea时,预览功能正常,但无法实现语法高亮
  • 改用contenteditable属性的div后,语法高亮正常,但出现两个问题:
    1. 预览面板输出undefined
    2. 输入HTML标签(如<h1>标题</h1>)会被直接渲染为元素,而非显示源码

修复方案

1. 修复预览undefined问题

contenteditable元素没有value属性,需通过innerText获取编辑器内容,替换原代码中document.getElementById("editor").value为document.getElementById("editor").innerText。

2. 实现源码显示(避免HTML渲染)

输入HTML特殊字符时,需将其转义为实体字符(<→&lt;,>→&gt;),确保浏览器将其视为文本而非HTML元素。同时在高亮处理时,基于转义后的内容生成带高亮的HTML。

3. 调整光标定位逻辑

修改innerHTML后光标会丢失,需重新计算光标位置,确保编辑体验流畅。


修改后的完整代码

index.html

<div id="editor" contenteditable="true" oninput="showPreview()">

<!-- HTML CODE TO PRINT -->
&lt;h1&gt;This is a Heading&lt;/h1&gt;
&lt;p&gt;This is a paragraph.&lt;/p&gt;
<!-- --&gt;

</div>

<h3>PREVIEW</h3>
<div class="preview-area">
  <iframe id="preview-window"></iframe>
</div>

style.css

#editor {
  width: 400px;
  height: 100px;
  padding: 10px;
  background-color: #444;
  color: white;
  font-size: 14px;
  font-family: monospace;
  white-space: pre-wrap; /* 保留换行和空格格式 */
}
.statement {
  color: orange;
}

javascript.js

// PREVIEW
function showPreview() {
    // 使用innerText获取编辑器文本内容
    var editorContent = document.getElementById("editor").innerText;
    var frame = document.getElementById("preview-window").contentWindow.document;
    frame.open();
    frame.write(editorContent);
    frame.close();
}

// 语法高亮与转义处理
var keywords = ["DIV", "H1", "P", "<", ">", "/"];

document.querySelector('#editor').addEventListener('keyup', e => {
    // 获取原始文本并转义特殊字符
    let rawText = e.target.innerText;
    let escapedText = rawText.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    
    // 分割文本并匹配关键词
    let chunks = escapedText.split(new RegExp(
        keywords.map(w => `(${w.replace(/[<>/]/g, '\\$&')})`).join('|'), 'i'
    )).filter(Boolean);
    
    // 生成高亮标记
    let markup = chunks.reduce((acc, chunk) => {
        let isKeyword = keywords.some(key => chunk.toUpperCase() === key.toUpperCase());
        acc += isKeyword ? 
            `<span class="statement">${chunk}</span>` : 
            `<span class='other'>${chunk}</span>`;
        return acc;
    }, '');
    
    e.target.innerHTML = markup;
    
    // 重新定位光标到文本末尾
    let range = document.createRange();
    let sel = window.getSelection();
    let lastChild = e.target.lastElementChild || e.target;
    range.setStart(lastChild, lastChild.textContent.length);
    range.collapse(true);
    sel.removeAllRanges();
    sel.addRange(range);
    e.target.focus();
});

内容的提问来源于stack exchange,提问作者Nodigap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:27:16