contentEditable:浏览器原生的富文本能力

目标

富文本编辑器的起点是浏览器提供的 contentEditable。本节课看透它的本质:它只是一个"允许用户在页面上直接改 DOM"的开关,所有格式都落在真实 DOM 上。理解这点,你就知道为什么自研编辑器既要利用它、又要管住它。

运行环境:任意现代浏览器(Chrome / Edge / Firefox / Safari)。
运行方式:把下面代码保存为 index.html,双击用浏览器打开,直接在框里输入、选中文字看效果。

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="utf-8">
  <title>最小富文本编辑器</title>
  <style>
    #editor { border: 1px solid #ccc; padding: 12px; min-height: 120px; outline: none; }
    #editor:focus { border-color: #10b981; }
  </style>
</head>
<body>
  <div id="editor" contenteditable="true">在这里输入文字,选中后按 Ctrl+B 看浏览器自带效果</div>
  <script>
    const editor = document.getElementById('editor')
    // 监听输入:每一次按键/格式变化都会触发
    editor.addEventListener('input', () => {
      console.log('当前 HTML =', editor.innerHTML)
    })
  </script>
</body>
</html>

打开后你会发现:回车会变成 <div> 或 <br>,按 Ctrl+B 浏览器会自动包 <b>。这些"自动行为"正是自研编辑器要精确控制的地方。

名词解释

contentEditable:HTML 全局属性。设成 "true" 后,该元素内的文字、图片可直接被用户编辑,改动直接写进 DOM。
DOM(文档对象模型):页面在内存里的树状结构。富文本编辑器操作的一切(文字、格式)最终都是这棵树上的节点。
input 事件:用户在可编辑区做任何修改(输入、删除、格式)都会触发,是"内容变了"的统一信号。

课后练习

练习:给上面的编辑器加一个按钮,点击后把当前内容通过 alert 弹出来。

答案:在 <body> 里加 <button id="show">显示 HTML</button>,脚本里加:

document.getElementById('show').addEventListener('click', () => {
  alert(editor.innerHTML)
})

总结

contentEditable 是富文本编辑器的"地基",但光有它远远不够。它的两个特点决定了你必须自己造一层:其一,格式是直接落在 DOM 上的,浏览器各内核生成的标签还不一致(Chrome 用 <div>、老 IE 用 <p>),导致同样的操作不同浏览器得到不同 HTML;其二,Ctrl+B 这类内置快捷键走的是已废弃的 execCommand,行为不可控、不可测。所以成熟编辑器的思路是:用 contentEditable 接收用户输入,但用一个自定义数据模型来决定"真正该生成什么 DOM"。第 1 节你只要记住一句话——contentEditable 给了你"能改",没给你"改得可控"。