• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

react-quill插件使用

武飞扬头像
Future_object
帮助1

一.安装

  1.  
    npm i react-quill
  2.  
    //图片放大缩小
  3.  
    npm i quill-image-resize-module-react

二.本人安装的插件版本

  1.  
    "react-quill": "^2.0.0",
  2.  
    "quill-image-resize-module-react": "^3.0.0",

三.代码封装一个插件(里面有问题的记录)

  1.  
    import { observer, useLocalObservable } from 'mobx-react';
  2.  
    import React, { useMemo, useRef,useEffect } from 'react';
  3.  
    import ReactQuill, { Quill } from 'react-quill';
  4.  
    import { uploadImg } from 'renderer/api/wxwork';
  5.  
    import { message, Spin } from 'antd';
  6.  
    import PropTypes from 'prop-types';
  7.  
    import ImageResize from 'quill-image-resize-module-react';
  8.  
     
  9.  
    /*
  10.  
    插件内部选中图片按删除键的时候导致以下报错(报错的原因是里面写了window.Quill.find):
  11.  
    Uncaught TypeError: Cannot read property 'find' of undefined
  12.  
    at HTMLDocument.checkImage (image-resize.min.js:formatted:1)
  13.  
    因此重写 ImageResize 模块里的checkImage 方法
  14.  
    */
  15.  
    class PlainResize extends ImageResize {
  16.  
    checkImage = (evt) => {
  17.  
    if (this.img) {
  18.  
    if (evt.keyCode === 46 || evt.keyCode === 8) {
  19.  
    Quill.find(this.img).deleteAt(0);
  20.  
    }
  21.  
    this.hide();
  22.  
    }
  23.  
    };
  24.  
    }
  25.  
     
  26.  
    Quill.register('modules/imageResize', PlainResize);
  27.  
     
  28.  
    // const mdEditorDomId = 'mdEditorDomId';
  29.  
     
  30.  
    const MdEditor = observer(function MdEditor(props) {
  31.  
    const mdEditorRef = useRef(null);
  32.  
     
  33.  
    const store = useLocalObservable(() => ({
  34.  
    loading: false,
  35.  
    setLoading(loading) {
  36.  
    this.loading = loading;
  37.  
    },
  38.  
    }));
  39.  
     
  40.  
    useEffect(() => {
  41.  
    // document.getElementById(mdEditorDomId).addEventListener('paste', handlerImagePaste, false);
  42.  
    // document.getElementById(mdEditorDomId).addEventListener('drop', handlerImageDrop, false);
  43.  
    // return () => {
  44.  
    // document.getElementById(mdEditorDomId).removeEventListener('paste', handlerImagePaste);
  45.  
    // document.getElementById(mdEditorDomId).removeEventListener('drop', handlerImageDrop);
  46.  
    // }
  47.  
    },[])
  48.  
     
  49.  
    async function submitImageUpload(file) {
  50.  
    const quillEditor = mdEditorRef.current?.getEditor();
  51.  
    const formData = new FormData();
  52.  
    formData.append('image', file);
  53.  
    store.setLoading(true);
  54.  
    try {
  55.  
    const { data: uploadImgData } = await uploadImg(formData);
  56.  
    const range = quillEditor.getSelection();
  57.  
    // 拖拽上传图片的时候,编辑器初始化时没有focus index就不存在,range为空
  58.  
    if (range) {
  59.  
    quillEditor.insertEmbed(range.index, 'image', uploadImgData.imgUrl); // 插入图片
  60.  
    } else {
  61.  
    // 获取内容的总长度(取最后的位置插入图片)
  62.  
    let valLength = mdEditorRef.current?.unprivilegedEditor?.getLength();
  63.  
    if (!valLength) {
  64.  
    valLength = 0;
  65.  
    }
  66.  
    quillEditor.insertEmbed(valLength, 'image', uploadImgData.imgUrl); // 插入图片
  67.  
    }
  68.  
    } catch (error) {
  69.  
    console.log(error);
  70.  
    if (error.isCodeErr) {
  71.  
    message.error(`图片上传失败,${error.msg}`);
  72.  
    } else {
  73.  
    message.error(`图片上传失败`);
  74.  
    }
  75.  
    } finally {
  76.  
    store.setLoading(false);
  77.  
    }
  78.  
    }
  79.  
     
  80.  
    function handleImageUpload() {
  81.  
    const input = document.createElement('input');
  82.  
    input.setAttribute('type', 'file');
  83.  
    input.setAttribute('accept', 'image/*');
  84.  
    input.click();
  85.  
    input.onchange = async () => {
  86.  
    const file = input.files[0];
  87.  
    submitImageUpload(file);
  88.  
    };
  89.  
    }
  90.  
    function handlerImagePaste(e) {
  91.  
    const { clipboardData } = e;
  92.  
    let blob;
  93.  
     
  94.  
    if (clipboardData) {
  95.  
    if (!clipboardData.items) {
  96.  
    return;
  97.  
    }
  98.  
    const types = clipboardData.types || [];
  99.  
     
  100.  
    for (let i = 0; i < types.length; i ) {
  101.  
    if (types[i] === 'Files') {
  102.  
    blob = clipboardData.items[i];
  103.  
    break;
  104.  
    }
  105.  
    }
  106.  
    if (blob && blob.kind === 'file') {
  107.  
    // 取消插件的默认事件
  108.  
    e.preventDefault();
  109.  
    if (blob.type.match(/^image\//i)) {
  110.  
    const file = blob.getAsFile();
  111.  
    submitImageUpload(file);
  112.  
    } else {
  113.  
    message.warning('仅支持上传图片!');
  114.  
    }
  115.  
    }
  116.  
    }
  117.  
    }
  118.  
     
  119.  
    function handlerImageDrop(e) {
  120.  
    // 取消插件的默认事件
  121.  
    e.preventDefault();
  122.  
    // 获取到第一个上传的文件对象
  123.  
    const file = e.dataTransfer.files[0];
  124.  
     
  125.  
    if (file.type.match(/^image\//i)) {
  126.  
    submitImageUpload(file);
  127.  
    } else {
  128.  
    message.warning('仅支持上传图片!');
  129.  
    }
  130.  
    }
  131.  
     
  132.  
    // 先不设置这个格式化,下次初始化编辑的时候会导致图片的宽高属性(width=“” height=““)丢失
  133.  
    // 现在还有一个问题,初始化编辑的时候,设不设置formats属性都会导致图片的style或者class之类的属性丢失,不过这个暂时不太影响,先放着(其他标签不会,只有img标签会这样)
  134.  
    // const formats = ['bold', 'italic', 'underline', 'strike', 'blockquote', 'list', 'bullet', 'indent', 'link', 'image'];
  135.  
     
  136.  
    // 里面加了handlers方法处理,不用useMemo这个编辑器会不展示
  137.  
    const modules = useMemo(
  138.  
    () => ({
  139.  
    toolbar: {
  140.  
    container: [
  141.  
    ['bold', 'italic', 'underline', 'strike', 'blockquote'],
  142.  
    [{ list: 'check' }, { list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: ' 1' }],
  143.  
    ['link', 'image'],
  144.  
    ['clean'],
  145.  
    ],
  146.  
    handlers: {
  147.  
    // 版本点击上传文件
  148.  
    image: handleImageUpload,
  149.  
    },
  150.  
    },
  151.  
    imageResize: {
  152.  
    parchment: Quill.import('parchment'),
  153.  
    // 先不要Toolbar这个图片位置调整的按钮,下次初始化编辑的时候会导致style样式丢失
  154.  
    // modules: ['Resize', 'DisplaySize', 'Toolbar']
  155.  
    modules: ['Resize', 'DisplaySize'],
  156.  
    },
  157.  
    }),
  158.  
    []
  159.  
    );
  160.  
     
  161.  
    /*
  162.  
    在ReactQuill的父容器加复制粘贴和拖拽事件,ReactQuill没有暴露这些事件
  163.  
    不用dom监听方法,避免dom有重复,导致监听重复
  164.  
    document.getElementById(mdEditorDomId).addEventListener('paste', handlerImagePaste, false);
  165.  
    document.getElementById(mdEditorDomId).addEventListener('drop', handlerImageDrop, false);
  166.  
    拖拽跟复制粘贴本来想着用 quill-image-extend-module 这个插件的,但是这个插画粘贴图片有问题
  167.  
    */
  168.  
    return (
  169.  
    <Spin spinning={store.loading} onPaste={handlerImagePaste} onDrop={handlerImageDrop}>
  170.  
    <ReactQuill
  171.  
    {...props}
  172.  
    ref={mdEditorRef}
  173.  
    theme="snow"
  174.  
    modules={modules}
  175.  
    // formats={formats}
  176.  
    // id={mdEditorDomId}
  177.  
    />
  178.  
    </Spin>
  179.  
    );
  180.  
    });
  181.  
     
  182.  
    MdEditor.propTypes = {};
  183.  
     
  184.  
    MdEditor.defaultProps = {};
  185.  
     
  186.  
    export default MdEditor;
学新通

四.使用

  1.  
    import MdEditor from './MdEditor';
  2.  
     
  3.  
    <MdEditor value={} onChange={} />

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfifici
系列文章
更多 icon
同类精品
更多 icon
继续加载