js实现富文本编辑器
使用 contenteditable 属性实现基础富文本编辑器
通过 HTML 的 contenteditable 属性可以让元素变为可编辑状态,这是实现富文本编辑器的基础。
<div id="editor" contenteditable="true"></div>
const editor = document.getElementById('editor');
editor.addEventListener('input', () => {
console.log(editor.innerHTML); // 获取编辑内容
});
使用 document.execCommand 实现文本格式化
document.execCommand 是传统富文本编辑的核心 API,支持加粗、斜体、插入链接等操作。
function formatText(command, value = null) {
document.execCommand(command, false, value);
}
// 示例:加粗选中文本
formatText('bold');
// 插入链接
formatText('createLink', 'https://example.com');
使用现代 API(如 Slate.js、ProseMirror)
传统 execCommand 已逐渐被废弃,现代富文本编辑器推荐使用库如 Slate.js 或 ProseMirror。
使用 Slate.js 示例
安装 Slate.js:
npm install slate slate-react
基础实现:

import { createEditor } from 'slate';
import { Slate, Editable, withReact } from 'slate-react';
const initialValue = [{ type: 'paragraph', children: [{ text: 'Hello World' }] }];
const editor = withReact(createEditor());
function App() {
return (
<Slate editor={editor} initialValue={initialValue}>
<Editable />
</Slate>
);
}
实现自定义工具栏
通过工具栏按钮调用 execCommand 或现代库的 API 实现交互。
<div class="toolbar">
<button onclick="formatText('bold')">Bold</button>
<button onclick="formatText('italic')">Italic</button>
</div>
<div id="editor" contenteditable="true"></div>
处理粘贴内容(防 XSS)
富文本编辑器需过滤粘贴的 HTML 内容以防止 XSS 攻击,可使用 DOMPurify 库。
import DOMPurify from 'dompurify';
editor.addEventListener('paste', (e) => {
e.preventDefault();
const text = e.clipboardData.getData('text/html');
const clean = DOMPurify.sanitize(text);
document.execCommand('insertHTML', false, clean);
});
保存与恢复内容
通过 localStorage 或后端 API 保存编辑内容。

// 保存内容
function saveContent() {
localStorage.setItem('editorContent', editor.innerHTML);
}
// 恢复内容
function loadContent() {
editor.innerHTML = localStorage.getItem('editorContent') || '';
}
支持 Markdown 输入
通过库如 marked 实现 Markdown 解析。
import { marked } from 'marked';
editor.addEventListener('input', () => {
const markdown = editor.textContent;
editor.innerHTML = marked.parse(markdown);
});
实现协同编辑(如 Y.js)
使用 Y.js 库实现多人实时协作编辑。
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';
const doc = new Y.Doc();
const provider = new WebsocketProvider('ws://localhost:1234', 'editor-room', doc);
const yText = doc.getText('content');
yText.observe(() => {
editor.innerHTML = yText.toString();
});
性能优化
对于大型文档,使用虚拟滚动(如 react-window)避免渲染卡顿。
import { FixedSizeList } from 'react-window';
const VirtualEditor = ({ content }) => (
<FixedSizeList height={600} itemCount={content.length} itemSize={35}>
{({ index, style }) => <div style={style}>{content[index]}</div>}
</FixedSizeList>
);






