在 React 项目中实现富文本编辑功能时,react-quill
是一个高效且灵活的解决方案。通过二次封装,我们可以统一配置、扩展功能并提升用户体验。本文将通过分步教程和实用技巧,助您打造功能强大的编辑器。
准备工作:安装依赖
npm install react-quill quill
确保同时安装 react-quill
和 quill
,前者提供 React 封装,后者为核心库。2. 创建封装组件
基础封装:创建可复用组件
创建 RichEditor.js
组件,封装基础配置:
import React, { Component, createRef } from 'react';
import ReactQuill, { Quill } from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import './custom-styles.css'; // 自定义样式文件
// 工具栏配置
const modules = {
toolbar: [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
['link', 'image', 'video'],
['clean']
]
};
// 支持的格式
const formats = [
'header', 'bold', 'italic', 'underline', 'strike',
'blockquote', 'code-block', 'list', 'bullet', 'link',
'image', 'video'
];
class RichEditor extends Component {
constructor(props) {
super(props);
this.state = { content: props.value || '' };
this.quillRef = createRef();
}
// 内容变化处理
handleChange = (content) => {
this.setState({ content });
this.props.onChange(content);
};
render() {
return (
<ReactQuill
ref={this.quillRef}
theme="snow"
value={this.state.content}
onChange={this.handleChange}
modules={modules}
formats={formats}
/>
);
}
}
export default RichEditor;
进阶功能扩展
1. 图片上传增强
// 在 RichEditor.js 中添加
imageHandler = () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.click();
input.onchange = () => {
const file = input.files[0];
if (file) this.uploadImage(file);
};
};
uploadImage = async (file) => {
try {
// 上传到服务器示例
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/upload-image', {
method: 'POST',
body: formData
});
const { url } = await response.json();
// 插入编辑器
const range = this.quillRef.current.getSelection();
this.quillRef.current.insertEmbed(range.index, 'image', url);
} catch (error) {
console.error('图片上传失败:', error);
}
};
componentDidMount() {
const quill = this.quillRef.current.getEditor();
quill.getModule('toolbar').addHandler('image', this.imageHandler);
}
2. 自定义样式
在 custom-styles.css
中覆盖默认样式:
.ql-container {
min-height: 400px;
border-radius: 8px;
border: 1px solid #e0e0e0;
}
.ql-toolbar {
border-radius: 8px 8px 0 0;
background-color: #f8f9fa;
}
.ql-editor {
padding: 1rem;
font-size: 16px;
line-height: 1.6;
}
使用示例:父组件集成
import React, { useState } from 'react';
import RichEditor from './RichEditor';
const App = () => {
const [editorContent, setEditorContent] = useState('');
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">我的博客编辑器</h1>
<RichEditor
value={editorContent}
onChange={setEditorContent}
placeholder="开始撰写你的内容..."
/>
{/* 实时预览 */}
<div className="mt-4 border rounded-lg p-4">
<h2 className="text-xl font-bold">预览</h2>
<div dangerouslySetInnerHTML={{ __html: editorContent }} />
</div>
</div>
);
};
实用技巧
1.动态禁用功能
// 通过条件渲染控制工具栏
const disabledModules = {
toolbar: {
container: [
['bold', { disabled: isReadOnly }],
// ...其他按钮
]
}
};
2.国际化支持
// 引入语言包
import { languages } from 'quill';
languages.zh = { /* 中文配置 */ };
Quill.register('locale/zh', languages.zh);
3.数据持久化
// 使用 localStorage 自动保存
useEffect(() => {
localStorage.setItem('editorContent', editorContent);
}, [editorContent]);
最佳实践总结
- 统一配置:将常用工具按钮和格式配置在封装组件中,避免重复代码
- 渐进扩展:从基础功能开始,逐步添加图片上传、视频嵌入等高级特性
- 样式隔离:使用 CSS Modules 或 styled-components 避免样式污染
- 性能优化:通过
shouldComponentUpdate
或 React.memo 优化渲染性能
这种封装方式非常适合在大型项目中使用,能够有效提高代码的可维护性和可复用性。