React富文本编辑器实现图片上传至后台的完整指南
一、选择合适的富文本编辑器
在React生态中,有多种富文本编辑器可供选择,如react-quill
、react-draft-wysiwyg
、ckeditor
等。每种编辑器都有其独特的特点和优势,本文将以react-quill
为例进行讲解。
1.1 安装react-quill
首先,需要在项目中安装react-quill
和quill
:
npm install react-quill quill
1.2 引入并使用react-quill
在React组件中引入react-quill
,并简单配置:
import React from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css'; // 引入样式
const MyEditor = () => {
const [content, setContent] = React.useState('');
const handleChange = (value) => {
setContent(value);
};
return <ReactQuill value={content} onChange={handleChange} />;
};
export default MyEditor;
二、实现图片上传功能
2.1 自定义图片上传处理
2.1.1 创建自定义Image模块
首先,创建一个自定义的Image模块:
const CustomImage = Quill.import('formats/image');
const ImageBlot = Quill.import('blots/image');
class CustomImageBlot extends ImageBlot {
static create(value) {
let node = super.create();
node.setAttribute('src', value.src);
return node;
}
static value(node) {
return { src: node.getAttribute('src') };
}
}
Quill.register(CustomImageBlot, true);
2.1.2 处理图片上传
const MyEditor = () => {
const [content, setContent] = React.useState('');
const quillRef = React.useRef(null);
const handleChange = (value) => {
setContent(value);
};
const handleImageUpload = (e) => {
const input = e.target;
const file = input.files[0];
const formData = new FormData();
formData.append('image', file);
// 发送图片至后台
fetch('/api/upload', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
const quill = quillRef.current.getEditor();
const range = quill.getSelection(true);
quill.insertEmbed(range.index, 'image', { src: data.url });
quill.setSelection(range.index + 1);
})
.catch(error => {
console.error('Error uploading image:', error);
});
};
React.useEffect(() => {
const quill = quillRef.current.getEditor();
const toolbar = quill.getModule('toolbar');
toolbar.addHandler('image', () => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = handleImageUpload;
});
}, []);
return <ReactQuill ref={quillRef} value={content} onChange={handleChange} />;
};
export default MyEditor;
2.2 后台处理图片上传
const express = require('express');
const multer = require('multer');
const app = express();
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname);
},
});
const upload = multer({ storage: storage });
app.post('/api/upload', upload.single('image'), (req, res) => {
const file = req.file;
if (file) {
res.json({ url: `/uploads/${file.filename}` });
} else {
res.status(400).send('No file uploaded.');
}
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
三、优化用户体验
3.1 图片上传进度提示
const handleImageUpload = (e) => {
const input = e.target;
const file = input.files[0];
const formData = new FormData();
formData.append('image', file);
// 显示上传进度
const quill = quillRef.current.getEditor();
const range = quill.getSelection(true);
quill.insertText(range.index, '上传中...', 'api');
quill.setSelection(range.index + 1);
fetch('/api/upload', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
quill.deleteText(range.index, '上传中...'.length);
quill.insertEmbed(range.index, 'image', { src: data.url });
quill.setSelection(range.index + 1);
})
.catch(error => {
quill.deleteText(range.index, '上传中...'.length);
quill.insertText(range.index, '上传失败', 'api');
console.error('Error uploading image:', error);
});
};
3.2 图片压缩与优化
npm install compressorjs
然后在handleImageUpload
函数中添加压缩逻辑:
import Compressor from 'compressorjs';
const handleImageUpload = (e) => {
const input = e.target;
const file = input.files[0];
new Compressor(file, {
quality: 0.8,
success(result) {
const formData = new FormData();
formData.append('image', result);
fetch('/api/upload', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
const quill = quillRef.current.getEditor();
const range = quill.getSelection(true);
quill.insertEmbed(range.index, 'image', { src: data.url });
quill.setSelection(range.index + 1);
})
.catch(error => {
console.error('Error uploading image:', error);
});
},
error(err) {
console.error('Error compressing image:', err.message);
},
});
};
四、总结
在实际开发中,你可能需要根据具体需求进行更多的定制和优化,但本文提供的基础框架和思路可以作为你进一步探索的起点。祝你开发顺利!