ueditor富文本复制粘贴含有图片的word内容处理,并且支持截图或单独复制图片粘贴

背景


公司最近升级项目,要求富文本支持含多图片的word的内容复制粘贴,没办法,为了用户体验只能去找解决方案,通过各种查资料,整理出来亲测有效的方案。

方案:1、监听粘贴事件,通过e.clipboardData 获取剪贴板里的信息

           2、获取图片的本地路径,同时通过rtf内容中查找图片数据

           3、把图片转为base64(没有做上传到服务器,后期有需要再加上)


实现步骤(代码都是在ueditor.all.js文件里修改)

1、定义变量并且找到ueditor初始化事件的代码(可以直接搜索“_initEvents”方法)

var wordImg = [];
_initEvents: function () {
                var me = this,
                    doc = me.document,
                    win = me.window;
            //*****************新增内容**********************************
                //监听word复制粘贴功能
                doc.addEventListener("paste", function (e) {
                    if (!(e.clipboardData && e.clipboardData.items)) {
                        return;
                    }                   
                    
                    /***
                     * 粘贴复制的图片,或是粘贴截图                     * 
                     */
                    const items = (e.clipboardData || window.clipboardData).items;
                    let file = null;
                    for (let i = 0; i < items.length; i++) {
                        if (items[i].type.indexOf("image") !== -1) {
                            file = items[i].getAsFile();
                            break;
                        }

                    }
                    me.fileToBase64(file,me)
                    /**
                     * 粘贴word文档
                     * */                
                    const clipboardData = e.clipboardData;   
                    //粘贴板中的HTML文本
                    let copyStr = clipboardData.getData('text/html');
                    //粘贴板中的RTF数据
                    let rtf = clipboardData.getData('text/rtf');

                    //获取粘贴板中图片的数量
                    let imgs = me.findAllImageElementsWithLocalSource(copyStr);

                    me.replaceImagesFileSourceWithInlineRepresentation(imgs, me.extractImageDataFromRtf(rtf))

                })
 //*****************新增内容**********************************
                me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
                domUtils.on(doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent);
                domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent);
                domUtils.on(me.body, 'drop', function (e) {
                    //阻止ff下默认的弹出新页面打开图片
                    if (browser.gecko && e.stopPropagation) { e.stopPropagation(); }
                    me.fireEvent('contentchange')
                });
                domUtils.on(doc, ['mouseup', 'keydown'], function (evt) {
                    //特殊键不触发selectionchange
                    if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
                        return;
                    }
                    if (evt.button == 2) return;
                    me._selectionChange(250, evt);
                });
            },

2、把方法复制进去

 //获取粘贴板中图片数量
            findAllImageElementsWithLocalSource: function (htmlData) {
                let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
                let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src             
                let arr = htmlData.match(imgReg); //筛选出所有的img
                if (!arr || (Array.isArray(arr) && !arr.length)) {
                    return false;
                }

                let srcArr = [];
                for (let i = 0; i < arr.length; i++) {
                    let src = arr[i].match(srcReg);
                    // 获取图片地址
                    srcArr.push(src[1]);
                }
                return srcArr;
            },
            //处理图片信息--从rtf内容中查找图片数据         
            extractImageDataFromRtf: function (rtfData, ignoreHeadersFooters = true) {
                if (!rtfData) {
                    return [];
                }

                const regexPictureHeader = /{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/
                const regexPicture = new RegExp('(?:(' + regexPictureHeader.source + '))([\\da-fA-F\\s]+)\\}', 'g');
                const images = rtfData.match(regexPicture);
                const result = [];

                if (images) {
                    for (const image of images) {
                        let imageType = false;

                        if (image.includes('\\pngblip')) {
                            imageType = 'image/png';
                        } else if (image.includes('\\jpegblip')) {
                            imageType = 'image/jpeg';
                        }

                        if (imageType) {
                            //是否跳过页眉页脚
                            if (ignoreHeadersFooters) {
                                const headerFooterRegex = /{\\header[\s\S]+?}\\par|{\\footer[\s\S]+?}\\par/g;
                                if (headerFooterRegex.test(image)) {
                                    continue;
                                }
                            }
                            result.push({
                                hex: image.replace(regexPictureHeader, '').replace(/[^\da-fA-F]/g, ''),
                                type: imageType
                            });
                        }
                    }
                }
                console.log(result)
                return result;
            },
            //16进制转换为base64
            _convertHexToBase64: function (hexString) {
                return btoa(hexString.match(/\w{2}/g).map(char => {
                    return String.fromCharCode(parseInt(char, 16));
                }).join(''));
            },

            //存储图片资源
            replaceImagesFileSourceWithInlineRepresentation: function (imageElements, imagesHexSources) {
                //如果有等量的图像元素和图像HEX源,可以根据现有顺序相应地匹配。
                if (imageElements.length === imagesHexSources.length) {
                    for (let i = 0; i < imageElements.length; i++) {
                        const newSrc = `data:${imagesHexSources[i].type};base64,${this._convertHexToBase64(imagesHexSources[i].hex)}`;
                        wordImg.push(newSrc);
                    }
                }
            },
             fileToBase64:function(file,_me) {
                return new Promise((resolve, reject) => {
                  // 创建一个新的 FileReader 对象
                  const reader = new FileReader();
                  // 读取 File 对象
                  reader.readAsDataURL(file);
                  // 加载完成后
                  reader.onload = function () {
                    // 将读取的数据转换为 base64 编码的字符串
                    const base64String ='data:image/jpeg;base64,'+ reader.result.split(",")[1];
                    // 解析为 Promise 对象,并返回 base64 编码的字符串
                    // resolve(base64String);
                    
                    _me.execCommand('inserthtml',`<img src=${base64String}>`);  
                  };
                  // 加载失败时
                  reader.onerror = function () {
                    reject(new Error("Failed to load file"));
                  };
                });
              },

3、在文件搜索 //todo base64 暂时去掉

    case 'img':
        //todo base64暂时去掉,后边做远程图片上传后,干掉这个
        if (val = node.getAttr('src')) {

        }
        node.setAttr('_src', node.getAttr('src'));
        break;

 

 4、替换inputRule内容

inputRule : function (root) {
    utils.each(root.getNodesByTagName('img'), function (img, key) {
        var attrs = img.attrs,
            flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
            opt = me.options,
            src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
        if (attrs['src'] && /^(?:(file:\/+))/.test(attrs['src'])) {
            img.setAttr({
                width:attrs.width,
                height:attrs.height,
                alt:attrs.alt,
                src:wordImg[key],
                'style':'background:url(' + ( flag ? opt.themePath + opt.theme + '/images/word.gif' : opt.langPath + opt.lang + '/images/localimage.png') + ') no-repeat center center;border:1px solid #ddd'
            })
        }
    })
    //清空调用记录
    wordImg = [];

}
 

 至此,整个UE编辑器可以支持word图文粘贴了。需要注意的是:本次修改没有将图片上传到后端服务器。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值