react-quill插件使用

一.安装

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={} />

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值