富文本编辑器是许多内容管理系统、协同办公应用和在线表单中的关键组件。它允许用户在浏览器中直接输入文字,并对文字应用加粗、斜体、下划线、撤销、重做等格式。相比普通文本框,富文本编辑器能够保留结构化内容;相比完全依赖鼠标点击的工具栏,快捷键操作能够明显减少手部在键盘与鼠标之间来回切换的成本。使用原生 JavaScript 实现一个基础版本,有助于理解可编辑区域、编辑命令、选区和键盘事件之间的关系。

构建可编辑区域与工具栏界面
实现这类编辑器的第一步,是让页面上的某个区域进入可编辑状态。浏览器提供了 contenteditable 属性,当一个普通的 HTML 元素设置该属性后,用户就可以在其中输入、删除和选中内容。通常会使用 <div> 元素作为编辑区域,因为它的块级布局更适合承载段落和行内样式。编辑器外部再包裹一个容器,用于统一控制宽度、边框和内部结构。
工具栏是编辑命令的可视化入口。加粗、斜体、下划线、撤销和重做可以分别对应不同的按钮。为了让脚本更容易维护,可以在按钮上保存命令名称,例如使用自定义数据属性记录 bold、italic、underline、undo 和 redo。这样后续只需要通过事件委托读取命令名,而不必为每个按钮单独编写点击逻辑。
界面样式也会影响编辑体验。编辑区域需要设置最小高度和内边距,避免输入内容过少时显得局促。工具栏按钮之间应保留间距,并通过悬停状态提示用户可点击。虽然编辑区域通常会移除默认的焦点边框,但建议通过更柔和的焦点样式给出视觉反馈,方便键盘用户确认当前输入位置。
<div class="editor-container">
<div class="toolbar">
<button type="button" data-command="bold" title="加粗">加粗</button>
<button type="button" data-command="italic" title="斜体">斜体</button>
<button type="button" data-command="underline" title="下划线">下划线</button>
<button type="button" data-command="undo" title="撤销">撤销</button>
<button type="button" data-command="redo" title="重做">重做</button>
</div>
<div class="edit-area" contenteditable="true">
在这里输入内容...
</div>
</div>
.editor-container {
width: 800px;
max-width: 100%;
border: 1px solid #ddd;
border-radius: 4px;
margin: 20px auto;
background-color: #fff;
}
.toolbar {
padding: 10px;
border-bottom: 1px solid #ddd;
background-color: #f5f5f5;
}
.toolbar button {
margin-right: 8px;
padding: 6px 12px;
border: 1px solid #ccc;
border-radius: 3px;
background-color: #fff;
cursor: pointer;
}
.toolbar button:hover {
background-color: #e9e9e9;
}
.edit-area {
min-height: 300px;
padding: 15px;
line-height: 1.6;
outline: none;
}
.edit-area:focus {
box-shadow: inset 0 0 0 2px rgba(80, 140, 250, 0.2);
}
通过编辑命令完成格式化操作
当编辑区域可以输入内容后,下一步是让工具栏按钮真正改变选中内容的样式。浏览器早期提供了 document.execCommand 方法,用来在当前选区上执行编辑命令。它的第一个参数是命令名称,第二个参数表示是否显示默认用户界面,第三个参数用于传递额外值。对于加粗、斜体、下划线、撤销和重做这些基础命令,通常不需要第三个参数,传入 null 即可。
在工具栏点击事件中,可以先判断事件来源是否是按钮,然后读取按钮上的命令数据。如果命令存在,就调用对应的编辑命令。这里使用事件委托的好处是结构清晰,即使后续增加新的按钮,只要保持相同的数据属性约定,脚本不需要频繁修改。
执行命令后还需要注意焦点问题。点击工具栏按钮时,编辑区域可能暂时失去焦点;如果焦点丢失,用户连续输入或继续操作时会感到不连贯。因此在执行命令后,可以再次调用编辑区域的 focus() 方法,让光标回到编辑区域。对于更复杂的编辑器,还需要在按钮按下阶段保持选区,但基础版本通过执行后聚焦已经能够满足常见演示需求。
// 获取工具栏和编辑区域
const toolbar = document.querySelector('.toolbar');
const editArea = document.querySelector('.edit-area');
// 监听工具栏点击事件
toolbar.addEventListener('click', function (event) {
const target = event.target;
// 只处理按钮点击
if (target.tagName !== 'BUTTON') {
return;
}
const command = target.dataset.command;
if (command) {
// 执行对应编辑命令
document.execCommand(command, false, null);
// 让编辑区域重新获得焦点
editArea.focus();
}
});
绑定快捷键并处理跨平台按键
快捷键的核心是监听编辑区域的键盘按下事件。当用户同时按下控制键和字母键时,程序需要识别组合并执行对应命令。在 Windows 和 Linux 环境中,常用控制键是 Ctrl;在 macOS 环境中,常用控制键是 Command。JavaScript 的键盘事件对象会提供 ctrlKey 和 metaKey 属性,只要其中一个为真,就可以认为用户按下了常见的命令修饰键。
识别具体按键时,可以读取 event.key,并将其转换为小写后比较。这样无论用户是否开启大写锁定,都能稳定匹配字母。对于加粗、斜体、下划线、撤销和重做,可以分别映射到 b、i、u、z 和 y。有些平台也习惯使用 Ctrl 加 Shift 加 Z 表示重做,因此在实现时可以同时兼容这种组合。
快捷键逻辑中一个关键步骤是调用 preventDefault()。浏览器或操作系统可能对某些按键组合有默认行为,如果不阻止,自定义命令可能和浏览器行为冲突,或者出现一次按键触发两次效果的问题。对于确定要接管的快捷键,应在执行命令前阻止默认行为,再调用编辑命令。
| 按键组合 | 命令 | 作用 |
|---|---|---|
| Ctrl 或 Command + B | bold | 加粗选中文本 |
| Ctrl 或 Command + I | italic | 将选中文本设置为斜体 |
| Ctrl 或 Command + U | underline | 给选中文本添加下划线 |
| Ctrl 或 Command + Z | undo | 撤销上一步操作 |
| Ctrl 或 Command + Y | redo | 重做被撤销的操作 |
| Ctrl 或 Command + Shift + Z | redo | 兼容部分平台的重做习惯 |
document.addEventListener('DOMContentLoaded', function () {
// 获取编辑器内部元素
const toolbar = document.querySelector('.editor-container .toolbar');
const editArea = document.querySelector('.editor-container .edit-area');
if (!toolbar || !editArea) {
return;
}
// 执行编辑命令并保持编辑区域焦点
function runCommand(command) {
if (!command) {
return;
}
document.execCommand(command, false, null);
editArea.focus();
}
// 工具栏点击事件
toolbar.addEventListener('click', function (event) {
const target = event.target;
if (target.tagName !== 'BUTTON') {
return;
}
runCommand(target.dataset.command);
});
// 快捷键事件
editArea.addEventListener('keydown', function (event) {
const hasModifier = event.ctrlKey || event.metaKey;
if (!hasModifier) {
return;
}
const key = event.key.toLowerCase();
let command = '';
if (key === 'b') {
command = 'bold';
} else if (key === 'i') {
command = 'italic';
} else if (key === 'u') {
command = 'underline';
} else if (key === 'z') {
if (event.shiftKey) {
command = 'redo';
} else {
command = 'undo';
}
} else if (key === 'y') {
command = 'redo';
}
if (command) {
event.preventDefault();
runCommand(command);
}
});
});
扩展方向与工程化注意事项
基础版本完成后,可以继续增加更多编辑能力。例如插入有序列表、无序列表、标题块、引用块、链接和字体颜色等。这些能力仍然可以沿用相同的模式:工具栏按钮保存命令名,脚本根据命令名执行操作。如果希望界面更友好,还可以在按钮的提示信息中标注快捷键,让用户在使用过程中逐步熟悉键盘操作。
粘贴内容往往是从外部网页或文档复制而来,可能携带大量不可控样式。如果直接允许富文本粘贴,编辑区域容易出现混乱的字体、颜色、行距和冗余结构。因此可以在粘贴事件中读取纯文本,再插入到编辑区域;或者先插入内容,再进行一次结构化清理。对于面向生产环境的项目,还需要在保存和渲染内容时进行安全过滤,避免脚本注入风险。
从长期维护角度看,document.execCommand 虽然使用简单,并且在当下仍被许多浏览器支持,但它已经被规范标记为不推荐继续使用。如果项目需要更稳定的选区控制、更细粒度的格式模型或跨浏览器一致行为,可以进一步研究 Selection 和 Range API,或者引入成熟的编辑器方案。不过,从学习原理和快速实现基础功能的角度来看,基于可编辑区域与编辑命令的实现方式仍然非常适合作为入门路径。
编辑器内容变化可以通过监听编辑区域的
input事件获取。拿到最新内容后,可以同步到表单字段、保存到服务端,或者实时生成预览效果。
总体来看,实现一个支持快捷键的富文本编辑器并不复杂:先搭建可编辑区域和工具栏,再通过编辑命令完成格式化操作,最后使用键盘事件绑定常见快捷键。掌握这条主线后,就可以根据业务需求逐步扩展粘贴处理、内容保存、样式过滤和更多命令,使编辑器从演示原型走向实际应用。
JavaScript富文本编辑器快捷键操作execCommand修改时间:2026-06-30 09:30:55