react(hooks)使用quill富文本编辑器(富文本中图片使用对象存储的方式)

难点:图片是对象存储,图片URL是存在有效期的,所以系统做了定时任务更新图片,数据库存储该字段内容时只存储对象存储的KEY(不存在URL),当定时任务来执行更新的时候,要查找到符文本中的图片KEY就相当的困难,甚至容易更新出错的可能
解决思路:富文本中存在的图片KEY,再单独创建一个字段存储(多个图片可以使用中间表或者用特殊符号分隔这些KEY),在查询时(或更新时)通过该字段中KEY先通过缓存拿到URL,然后去富文本内容中通过KEY替换成URL,达到前端显示是图片URL,存储在表中是KEY,定时任务只需要更新存储KEY的字段到缓存即可

  1. 安装quill
npm i react-quill --save
npm i quill --save
  1. 封装成组件的方式使用
import React, {useEffect} from 'react';
import {message} from 'antd';
import Quill from 'quill';
import 'react-quill/dist/quill.snow.css';
import {uploadInfoImage} from '../apis/index';

/**
 * quill富文本编辑器
 * @param setQuillMaps 存储ecs对象
 * @param setDataLoading
 * @desc
 * 内容回显: document.getElementById('id').children[0].innerHTML = '';
 * 内容获取: document.getElementById('id').children[0].innerHTML;
 * @returns {*}
 * @constructor
 */
const QuillEditor = ({setQuillMaps, setDataLoading}) => {
    //只能使用这种方式,useState()的方式不行
    let quill = {};
    //创建一个map存储富文本上传的图片,ecsKEY作为map的key,ecsURL作为map的value
    const quillImages = [];

    useEffect(() => {
        // eslint-disable-next-line react-hooks/exhaustive-deps
        quill = new Quill('#quill-editor', {
            // 设置主题
            theme: 'snow',
            modules: {
                toolbar: {
                    container: [
                        [{'header': [1, 2, false]}],
                        ['bold', 'italic', 'underline', 'strike', 'blockquote'],
                        [{'align': []}],
                        [{'color': []}],
                        [{'indent': '-1'}, {'indent': '+1'}],
                        [{'list': 'ordered'}, {'list': 'bullet'}],
                        [{'direction': 'rtl'}],
                        ['link', 'image', 'video'],
                        ['clean']
                    ],
                    handlers: {
                        image() {
                            imageHandler();
                        }
                    }
                }
            }
        });
    }, []);

    const imageHandler = () => {
        const input = document.createElement('input');
        input.setAttribute('type', 'file');
        input.setAttribute('accept', 'image/*');
        input.click();

        input.onchange = async () => {
            const formData = new FormData();
            formData.append('infoImage', input.files[0]);

            try {
                setDataLoading(true);
                const {key, url} = await uploadInfoImage(formData);
                setDataLoading(false);
                if (!key || !url) {
                    message.error('图片上传失败');
                } else {
                    quillImages.push({key, url});
                    setQuillMaps(quillImages);
                    //获取当前光标位置
                    const selection = quill.getSelection();
                    //插入图片
                    quill.insertEmbed(selection.index, 'image', url);
                    //光标位置加1
                    quill.setSelection(selection.index + 1);
                }
            } catch (e) {
                setDataLoading(false);
                message.error('图片上传出错');
            }
        };
    };

    return (
        <div id="quill-editor" />
    );
};

export default QuillEditor;
  1. 引入使用
//setQuillMaps:存储富文本中上传的图片,单独用字段存起来;setDataLoading是上传图片的加载
<QuillEditor setQuillMaps={setQuillMaps} setDataLoading={setDataLoading} />
  1. 富文本回显内容
document.getElementById('quill-editor').children[0].innerHTML = data['info'];
  1. 获取富文本的内容
const infoTxt = document.getElementById('quill-editor').children[0].innerHTML;
  1. 处理符文本的图片(特别重要,如果存在修改的情况,需要区分历史上传的图片和本次上传的图片)
    infoImages 是单独作为字段传到后台存到单独的字段中
const infoImages = [];
if (!isEmpty(oldQuillMaps)) {
    infoImages.push(...oldQuillMaps);
}
if (!isEmpty(quillMaps)) {
    infoImages.push(...quillMaps);
}
  1. 后端存库处理
//处理内容富文本的html内容
List<String> newKeys = new ArrayList<>();
final String[] info = {shop.getInfo()};
logger.info("info[0]========>" + info[0]);
List<ECSBean> quillMaps = shop.getQuillMaps();
if (StringUtils.isNotEmpty(info[0]) && CollectionUtil.isNotEmpty(quillMaps)) {
    //说明内容有值,并且传了图片,那么用quillMaps里的key替换掉info里的URL,才能存到数据库
    Map<String, String> map = quillMaps.stream().collect(Collectors.toMap(ECSBean::getKey, ECSBean::getUrl, (key1, key2) -> key2));
    //keys = quillMaps.stream().map(ECSBean::getKey).distinct().collect(Collectors.toList());
    List<String> keys = new ArrayList<>(map.keySet());
    keys.stream().forEach(key -> {
        String url = map.get(key).replaceAll(" ", "");
        logger.info("url=============>" + url);
        if (info[0].contains(url)) {
            info[0] = info[0].replace(url, String.valueOf(key));

            //把url缓存到数据库
            asyncService.updateShopInfoImages(key, url);

            //处理key(因为存在删除图片)
            newKeys.add(key);
        }
    });
}
shop.setInfo(info[0]);

String infoImages = newKeys.toString()
        .replaceAll(",", "~")
        .replaceAll("\\[", "")
        .replaceAll("]", "")
        .replaceAll(" ", "");
shop.setInfoImages(infoImages);
  1. 查询时需要处理
//处理内容富文本的html内容
final String[] info = {shop.getInfo()};
 List<ECSBean> quillMaps = new ArrayList<>();
 String infoImages = shop.getInfoImages();
 if (StringUtils.isNotEmpty(info[0]) && StringUtils.isNotEmpty(infoImages)) {
     List<String> ecsKeys = new ArrayList<>();
     if (infoImages.contains("~")) {
         ecsKeys.addAll(Arrays.asList(infoImages.split("~")));
     } else {
         ecsKeys.add(infoImages);
     }

     ecsKeys.stream().forEach(ecsKey -> {
         if (info[0].contains(ecsKey)) {
             String url = redisHelper.getStr(Consts.appCode + "-shop-info-images-" + ecsKey);
             if (StringUtils.isEmpty(url)) {
                 url = storeService.getUrl(ecsKey);
                 //再更新到缓存
                 asyncService.updateShopInfoImages(ecsKey, url);
             }
             info[0] = info[0].replace(ecsKey, url);
             quillMaps.add(new ECSBean(ecsKey, url));
         }
     });
     shop.setInfo(info[0]);
     shop.setQuillMaps(quillMaps);
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值