一.安装
npm i react-quill
//图片放大缩小
npm i quill-image-resize-module-react
二.本人安装的插件版本
"react-quill": "^2.0.0",
"quill-image-resize-module-react": "^3.0.0",
三.代码封装一个插件(里面有问题的记录)
import { observer, useLocalObservable } from 'mobx-react';
import React, { useMemo, useRef,useEffect } from 'react';
import ReactQuill, { Quill } from 'react-quill';
import { uploadImg } from 'renderer/api/upload';
import { message, Spin } from 'antd';
import PropTypes from 'prop-types';
import ImageResize from 'quill-image-resize-module-react';
/*
插件内部选中图片按删除键的时候导致以下报错(报错的原因是里面写了window.Quill.find):
Uncaught TypeError: Cannot read property 'find' of undefined
at HTMLDocument.checkImage (image-resize.min.js:formatted:1)
因此重写 ImageResize 模块里的checkImage 方法
*/
class PlainResize extends ImageResize {
checkImage = (evt) => {
if (this.img) {
if (evt.keyCode === 46 || evt.keyCode === 8) {
Quill.find(this.img).deleteAt(0);
}
this.hide();
}
};
}
Quill.register('modules/imageResize', PlainResize);
// const mdEditorDomId = 'mdEditorDomId';
const MdEditor = observer(function MdEditor(props) {
const mdEditorRef = useRef(null);
const store = useLocalObservable(() => ({
loading: false,
setLoading(loading) {
this.loading = loading;
},
}));
useEffect(() => {
// document.getElementById(mdEditorDomId).addEventListener('paste', handlerImagePaste, false);
// document.getElementById(mdEditorDomId).addEventListener('drop', handlerImageDrop, false);
// return () => {
// document.getElementById(mdEditorDomId).removeEventListener('paste', handlerImagePaste);
// document.getElementById(mdEditorDomId).removeEventListener('drop', handlerImageDrop);
// }
},[])
async function submitImageUpload(file) {
const quillEditor = mdEditorRef.current?.getEditor();
const formData = new FormData();
formData.append('image', file);
store.setLoading(true);
try {
const { data: uploadImgData } = await uploadImg(formData);
const range = quillEditor.getSelection();
// 拖拽上传图片的时候,编辑器初始化时没有focus index就不存在,range为空
if (range) {
quillEditor.insertEmbed(range.index, 'image', uploadImgData.imgUrl); // 插入图片
} else {
// 获取内容的总长度(取最后的位置插入图片)
let valLength = mdEditorRef.current?.unprivilegedEditor?.getLength();
if (!valLength) {
valLength = 0;
}
quillEditor.insertEmbed(valLength, 'image', uploadImgData.imgUrl); // 插入图片
}
} catch (error) {
console.log(error);
if (error.isCodeErr) {
message.error(`图片上传失败,${error.msg}`);
} else {
message.error(`图片上传失败`);
}
} finally {
store.setLoading(false);
}
}
function handleImageUpload() {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async () => {
const file = input.files[0];
submitImageUpload(file);
};
}
function handlerImagePaste(e) {
const { clipboardData } = e;
let blob;
if (clipboardData) {
if (!clipboardData.items) {
return;
}
const types = clipboardData.types || [];
for (let i = 0; i < types.length; i++) {
if (types[i] === 'Files') {
blob = clipboardData.items[i];
break;
}
}
if (blob && blob.kind === 'file') {
// 取消插件的默认事件
e.preventDefault();
if (blob.type.match(/^image\//i)) {
const file = blob.getAsFile();
submitImageUpload(file);
} else {
message.warning('仅支持上传图片!');
}
}
}
}
function handlerImageDrop(e) {
// 取消插件的默认事件
e.preventDefault();
// 获取到第一个上传的文件对象
const file = e.dataTransfer.files[0];
if (file.type.match(/^image\//i)) {
submitImageUpload(file);
} else {
message.warning('仅支持上传图片!');
}
}
// 先不设置这个格式化,下次初始化编辑的时候会导致图片的宽高属性(width=“” height=““)丢失
// 现在还有一个问题,初始化编辑的时候,设不设置formats属性都会导致图片的style或者class之类的属性丢失,不过这个暂时不太影响,先放着(其他标签不会,只有img标签会这样)
// const formats = ['bold', 'italic', 'underline', 'strike', 'blockquote', 'list', 'bullet', 'indent', 'link', 'image'];
// 里面加了handlers方法处理,不用useMemo这个编辑器会不展示
const modules = useMemo(
() => ({
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{ list: 'check' }, { list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
['link', 'image'],
['clean'],
],
handlers: {
// 版本点击上传文件
image: handleImageUpload,
},
},
imageResize: {
parchment: Quill.import('parchment'),
// 先不要Toolbar这个图片位置调整的按钮,下次初始化编辑的时候会导致style样式丢失
// modules: ['Resize', 'DisplaySize', 'Toolbar']
modules: ['Resize', 'DisplaySize'],
},
}),
[]
);
/*
在ReactQuill的父容器加复制粘贴和拖拽事件,ReactQuill没有暴露这些事件
不用dom监听方法,避免dom有重复,导致监听重复
document.getElementById(mdEditorDomId).addEventListener('paste', handlerImagePaste, false);
document.getElementById(mdEditorDomId).addEventListener('drop', handlerImageDrop, false);
拖拽跟复制粘贴本来想着用 quill-image-extend-module 这个插件的,但是这个插画粘贴图片有问题
*/
return (
<Spin spinning={store.loading} onPaste={handlerImagePaste} onDrop={handlerImageDrop}>
<ReactQuill
{...props}
ref={mdEditorRef}
theme="snow"
modules={modules}
// formats={formats}
// id={mdEditorDomId}
/>
</Spin>
);
});
MdEditor.propTypes = {};
MdEditor.defaultProps = {};
export default MdEditor;
四.使用
import MdEditor from './MdEditor';
<MdEditor value={} onChange={} />