contenteditable 可编辑
contenteditable 全局属性使元素变为可编辑区域,用户可以直接在页面上修改文本内容。它是富文本编辑器的基础,支持文本格式化、图片插入等操作。
前置知识
阅读本节前,建议先了解:draggable 拖拽
基础概念
contenteditable 的值
| 值 | 说明 | 用途 |
|---|---|---|
true | 可编辑 | 富文本编辑区域 |
false | 不可编辑 | 显式标记只读内容 |
plaintext-only | 仅纯文本 | 只允许纯文本输入 |
基本用法
html
<!-- 可编辑区域 -->
<div contenteditable="true" style="border:1px solid #ccc;padding:1rem;min-height:100px;">
<p>点击这里开始编辑...</p>
</div>
<!-- 纯文本编辑 -->
<div contenteditable="plaintext-only" style="border:1px solid #ccc;padding:1rem;">
只能输入纯文本
</div>
<!-- 混合使用:段落内局部可编辑 -->
<div>
<p>这段文字不可编辑。</p>
<p contenteditable="true">这段文字可以编辑。</p>
<p>这段文字不可编辑。</p>
</div>语法与使用
execCommand API
contenteditable 配合 document.execCommand() 实现富文本编辑:
javascript
// 执行格式化命令
document.execCommand("bold"); // 加粗
document.execCommand("italic"); // 斜体
document.execCommand("underline"); // 下划线
document.execCommand("strikethrough"); // 删除线
document.execCommand("foreColor", false, "red"); // 文字颜色
document.execCommand("fontSize", false, "5"); // 字号
document.execCommand("insertUnorderedList"); // 无序列表
document.execCommand("insertHTML", false, "<b>插入的内容</b>");
// 检查当前状态
document.queryCommandState("bold"); // 是否加粗
document.queryCommandValue("foreColor"); // 当前颜色spellcheck 配合使用
html
<!-- 启用拼写检查 -->
<div contenteditable="true" spellcheck="true">
<p>编辑内容会检查拼写。</p>
</div>
<!-- 禁用拼写检查(适合代码编辑) -->
<div contenteditable="true" spellcheck="false">
<code>var x = 42;</code>
</div>详细说明
beforeinput 和 input 事件
html
<div contenteditable="true" id="editor"></div>
<script>
const editor = document.getElementById("editor");
// beforeinput 事件:输入前触发(可以拦截)
editor.addEventListener("beforeinput", (e) => {
console.log("输入类型:", e.inputType);
console.log("输入数据:", e.data);
// 阻止某些输入
if (e.inputType === "insertParagraph" && e.data === "HTML") {
e.preventDefault();
}
});
// input 事件:输入完成后触发
editor.addEventListener("input", (e) => {
console.log("内容已更改");
const text = editor.innerText; // 获取纯文本
const html = editor.innerHTML; // 获取 HTML
});
</script>contenteditable 的注意事项
| 注意事项 | 说明 |
|---|---|
| XSS 风险 | 富文本编辑器允许用户输入 HTML,可能导致 XSS 攻击 |
| 粘贴处理 | 从其他应用粘贴的内容可能携带不期望的格式 |
| execCommand 废弃 | 虽然仍可用,但建议迁移到 Input Events API |
| 移动端兼容 | 移动设备的虚拟键盘与 contenteditable 交互复杂 |
实战示例
简易富文本编辑器
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>contenteditable 编辑器示例</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, sans-serif; padding: 2rem; }
.toolbar {
display: flex; gap: 0.25rem; padding: 0.5rem;
background: #f1f5f9; border-radius: 8px 8px 0 0;
border: 1px solid #e2e8f0; border-bottom: none;
flex-wrap: wrap;
}
.toolbar button {
padding: 0.4rem 0.75rem; border: 1px solid #d1d5db;
border-radius: 4px; background: #fff; cursor: pointer;
font-size: 0.85rem;
}
.toolbar button:hover { background: #e2e8f0; }
.editor {
border: 1px solid #e2e8f0; border-radius: 0 0 8px 8px;
padding: 1rem; min-height: 200px; outline: none;
line-height: 1.6;
}
.editor:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59,130,246,0.1);
}
.info {
margin-top: 1rem; padding: 1rem; background: #f8fafc;
border-radius: 6px; font-size: 0.9rem;
}
</style>
</head>
<body>
<h1>简易富文本编辑器</h1>
<div class="toolbar">
<button onclick="exec('bold')" title="加粗"><b>B</b></button>
<button onclick="exec('italic')" title="斜体"><i>I</i></button>
<button onclick="exec('underline')" title="下划线"><u>U</u></button>
<button onclick="exec('strikethrough')" title="删除线"><s>S</s></button>
<button onclick="exec('insertUnorderedList')" title="无序列表">•</button>
<button onclick="exec('foreColor', false, 'red')" title="红色">A(红)</button>
<button onclick="exec('foreColor', false, 'blue')" title="蓝色">A(蓝)</button>
<button onclick="exec('fontSize', false, '5')" title="大字号">大</button>
</div>
<div class="editor" contenteditable="true">
<p>在这里编辑内容...</p>
<p>支持<b>加粗</b>、<i>斜体</i>、<u>下划线</u>等格式。</p>
</div>
<div class="info">
<p>当前内容:<span id="char-count">0</span> 字符</p>
</div>
<script>
function exec(command, value) {
document.execCommand(command, false, value || null);
}
const editor = document.querySelector('.editor');
const charCount = document.getElementById('char-count');
editor.addEventListener('input', () => {
charCount.textContent = editor.innerText.length;
});
</script>
</body>
</html>注意事项
- 安全性:必须对用户输入进行消毒处理,防止 XSS
- 跨浏览器差异:不同浏览器的粘贴行为和格式化不一致
- 移动端兼容:移动设备的虚拟键盘与 contenteditable 交互复杂
- 性能:大量内容时 contenteditable 可能导致卡顿
最佳实践
- 使用 plaintext-only:如果不需要富文本,使用纯文本模式
- 配合 spellcheck:根据内容类型启用或禁用拼写检查
- 监听 input 事件:使用 Input Events API 实时获取内容变化
- 消毒输出:显示内容时过滤危险的 HTML 标签
- 考虑成熟编辑器:生产环境建议使用 Quill、TinyMCE 等成熟方案
下一节
继续学习:spellcheck 拼写检查