Skip to content

Latest commit

 

History

History
34 lines (16 loc) · 4.62 KB

富文本编辑器4~站外图片的粘贴.md

File metadata and controls

34 lines (16 loc) · 4.62 KB

富文本编辑器4~站外图片的粘贴

业务场景分析

在第二篇文章中,介绍过如何进行站外内容的复制粘贴,当时将html元素都转换为带段落的文字,并且将图片等其它标签直接去掉了。

这样做,对用户的使用并不友好,用户想把站外的文章连文字一起粘贴到本站的过程,被割裂了,所以,要想办法将站外图片一并粘贴过来。

方案过程

在粘贴的时候,我们获得的剪贴板的内容其实是一段html字符串.

首先我们要将html字符串中的图片元素的src获得到,然后想办法将图片的url转存到我们自己的文件服务器上。

这里我们使用了七牛的url转存服务,简单来说,这个服务的输入就是一个第三方的图片url,返回就是,这个图片被转存到七牛我们自己账户下面后的url。真是轻松加愉快。

但是要注意的是,这个过程可能会比较慢,也会有失败的可能性,所以要做好特殊情况的处理。

再获得了我们自己的图片url后,我们需要将原有的html字符串中的图片替换为我们自己的url,然后删掉没用的html标签和样式,再粘贴到我们的编辑器中就可以了。

应用了这个方案后,再大部分情况下,用户可以直接ctrl + a,ctrl + c, ctrl + v,就将一篇完整的带图片的文章粘贴到我们的编辑器中了。

关键代码


dealOutter = (text, html) => { // 站外处理
    if (html.indexOf('<img ') === -1) { // 没有图片 走原来的算法
        this.pasteText(text, html);
    } else {
        this.pasteSelection = document.getSelection().getRangeAt(0);
        this.userCancelPaste = false;
        const uploadId = String(window.Math.random()); // 上传id 保证多线程操作不会互相影响
        this.uploadId = uploadId;
        const imgs = html.match(/<img [^>]+>/g);
        for (let i = 0; i < imgs.length; i += 1) {
            // todo 容错 和 兼容不同网站
            imgs[i] = imgs[i].match(/src="[^"]+"/)[0]
                .replace('src="', '')
                .replace('"', '')
                .replace(/&amp;/g, '&');
        }
        let html2 = html.replace(/<img [^>]+>/g, '@@@@BBT_IMG@@@@');
        html2 = html2
            .replace(/<\/p>/g, '\n')
            .replace(/<\/div>/g, '\n')
            .replace(/<br>/g, '\n')
            .replace(/<[^>]+>/g, '')
            .replace(/&nbsp;/g, ' ');
        this.parseImgUrls(imgs, html2, 0, uploadId);
    }
}


parseImgUrls = (imgs2, html, index, uploadId) => {
    if (this.isCanceled(uploadId)) {
        return;
    }
    const imgs = imgs2;
    const fd = new window.FormData();
    this.showMsg(`<br/>您粘贴的内容中含有${imgs.length}张图片<br/>正在处理第${index + 1}张...`);
    fd.append('url_list[]', [imgs[index]]);
    window.fetch('/image/upload_by_urls', {
        method: 'POST',
        credentials: 'include',
        body: fd,
    })
        .then(res => res.json())
        .then((res) => {
            if (res.status !== 'success' || res.data.length !== 1 || !res.data[0].photo_id) {
                imgs[index] = { t: '100', url: errorImgSrc, alt: '图片解析失败.' };
            } else {
                imgs[index] = res.data[0];
            }
            this.parseImgUrl(imgs, html, index, uploadId);
        })
        .catch((e) => {
            console.log(e);
            imgs[index] = { t: '100', url: errorImgSrc, alt: '图片解析失败.' };
            this.parseImgUrl(imgs, html, index, uploadId);
        });
}

parseImgUrl = (imgs, html, index, uploadId) => {
    if (this.isCanceled(uploadId)) {
        return;
    }
    if (imgs.length - 1 === index) { // 最后一个
        const texts = html.split('@@@@BBT_IMG@@@@');
        document.getSelection().removeAllRanges();
        document.getSelection().addRange(this.pasteSelection);
        texts.map((text, i) => {
            document.execCommand('insertText', false, text);
            if (i < imgs.length) {
                const json = {
                    t: imgs[i].t || '2',
                    id: imgs[i].photo_id,
                    path: imgs[i].url,
                };
                const imgHtml = `<img alt="${imgs[i].alt}" src="${imgs[i].url}" ${BBT_JSON}='${JSON.stringify(json)}' />`;
                document.execCommand('insertHtml', false, imgHtml);
            }
            return null;
        });
        this.hideMsg();
    } else {
        this.parseImgUrls(imgs, html, index + 1, uploadId);
    }
}