textarea本身不支持语法高亮,因其为表单控件,内容仅能通过.value读写,innerhtml始终为空;强行操作会导致光标跳动、粘贴错乱等规范行为,必须用codemirror等方案将样式层与输入层物理分离。

textarea 本身不支持语法高亮——这是浏览器原生限制,任何试图直接给 textarea 加 contenteditable 或内嵌 style 的方案,都会导致光标跳动、粘贴错乱、换行异常,甚至在 Chrome 120+ 中完全失效。
为什么不能直接操作 textarea 的 innerHTML
因为 textarea 是表单控件,它的内容只能通过 .value 读写;innerHTML 永远为空,强行设置会静默失败。有人用 font 标签包裹文本再塞进去,结果发现:复制时带标签、回车后光标归零、全选失效——这不是 bug,是规范行为。
- 所有样式层必须和输入层物理分离(比如用绝对定位的
div覆盖在textarea上) - 光标位置必须实时同步:监听
input和keydown,用getSelectionRangeAt(0)或selectionStart获取偏移 - 高亮层需按 token 切分渲染,不能整段
innerHTML = highlightedText,否则光标重置
CodeMirror 是最稳的「伪 textarea」方案
它本质是用 div 模拟编辑器视图,把真实 textarea 当作数据源隐藏起来。初始化后,你拿到的是 editor 实例,不是 DOM 元素。
- 必须显式引入对应语言模式:
htmlmixed.min.js(不是html.min.js),否则<script></script>内 JS 不高亮 - 行号开启要配
lineNumbers: true,否则左侧空白区不会出现数字 - 获取值必须用
editor.getValue(),不要读textarea.value——它可能还是旧内容 - 提交前若需原始字符串(比如含未转义
),调用 <code>editor.toTextArea()再取textarea.value
Prism.js 只适合静态展示,别硬套进编辑场景
它设计目标就是「渲染一次就完事」,没有光标管理、无增量更新、不响应输入。如果你看到网上有人用 Prism.highlightElement() 配合 input 事件反复调用,那页面大概率已卡顿或高亮错位。
- 自动高亮只认
<pre class="brush:php;toolbar:false;"><code class="html"></code></pre> - class 值写成
lang-html或language-html才生效,html单独写无效 - 代码里的
必须手动转义为 <code><,否则被浏览器解析成标签而丢失 - 想保留原始符号?把代码塞进
<script type="text/plain"></script>,再用.textContent提取
自己实现轻量高亮层要注意的三个硬伤
如果项目极小、只需 HTML 标签变色(不涉及属性/注释/JS 嵌入),可基于 textarea + 绝对定位 div 自建。但以下三点漏掉一个,用户就会骂娘:
- 光标同步必须用
setSelectionRange()主动恢复,不能依赖浏览器默认行为 - 高亮
div的font-family、line-height、padding必须和textarea完全一致,否则位置偏移 - 每次输入后,要根据
textarea.value重新生成高亮 HTML,并用textContent+ 正则替换构造带span的结构,避免 XSS
真正难的不是颜色,是让光标不跳、换行不崩、粘贴不乱——这些细节没暴露在控制台里,但用户一秒就能感知。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











