使用html2canvas将整个元素导出为图片,其中包含svg和img,解决img跟svg导出时img或svg(canvg处理)不显示的问题,以及相关优化

目录

前言

一、准备

二、解决问题

1.将svg跟img转为canvas的方法

2.将base64转换成file文件的方法

3.点击下载使用方法

1).对dom没有处理,需求只是将图片导出即可

 2).涉及对dom的拖拽,流程图之类的(需复制dom,在复制的dom上进行处理)

 三、效果图如下


前言

查阅很多相关的文章和文档,大多是解决svg导出不显示的问题,这个还是比较好处理的。但是对于我的需求而言,主要问题是,需要导出成图片的dom元素,中间既有img又有svg,导致我在导出时,img的元素并没有显示在导出的图片上

一、准备

我使用的html2canvas版本是1.4.1 ,canvg版本是1.5.3

npm install --save [email protected]
npm install --save [email protected]

引入组件

import html2canvas from "html2canvas";
import canvg from "canvg";

二、解决问题

1.将svg跟img转为canvas的方法

changeToCanvas(element) {
    const svgElems = element.querySelectorAll('svg');
    const imgElems = element.querySelectorAll('img');
    //es6语法
    let elems = [...svgElems, ...imgElems]
    elems.forEach(node => {
        let parentNode = node.parentNode;
        let canvas = document.createElement("canvas");
        canvas.style.zIndex = 9
        //处理svg转换canvas需要使用canvg组件
        if (node.tagName == 'svg') {
            let svg = node.outerHTML.trim();
            canvg(canvas, svg);
            if (node.style.position) {
                canvas.style.position += node.style.position;
                canvas.style.left += node.style.left;
                canvas.style.top += node.style.top;
            }
        } 
        //处理img转换canvas
        if (node.tagName == 'IMG') {
            canvas.width = node.width;
            canvas.height = node.height;
            canvas.getContext("2d").drawImage(node, 0, 0)
        }
        parentNode.removeChild(node);
        parentNode.appendChild(canvas);
    });
}

2.将base64转换成file文件的方法

base64ToFile(dataurl) {
    let arr = dataurl.split(',');
    let mime = arr[0].match(/:(.*?);/)[1];
    let bstr = atob(arr[1]);
    let n = bstr.length;
    let u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {
        type: mime
    });
},

3.点击下载使用方法

downloadIMG()这个方法中,由于我是svg制作流程图,避免下载后导致无法拖拽svg,所以我这里的做法是先复制一个临时元素,在使用完后再清除掉,如果说你本身不对svg以及img做一些操作的话,可以不需要这几步。

scale属性可以解决解决生成的canvas模糊问题

1).对dom没有处理,需求只是将图片导出即可

downloadIMG() {
    //需要在id为flowWrap的div里面加上 ref="flowWrap"
    const flow = this.$refs.flowWrap
    flow.style.background = '#000'
    //调用changeToCanvas
    this.changeToCanvas(flow)
    html2canvas(flow, {
        taintTest: false,
        scale: window.devicePixelRatio < 2 ? 2 : window.devicePixelRatio, //scala属性解决生成的canvas模糊问题
    }).then((canvas) => {
        //调用base64ToFile
        let blob = this.base64ToFile(canvas.toDataURL('image/png'));
        let a = document.createElement('a');
        a.setAttribute('href', URL.createObjectURL(blob));
        a.setAttribute('download', new Date().getTime() + '.png');
        URL.revokeObjectURL(blob);
        a.click();
        a.remove();
        //element组件,你可以直接使用alert查看
        this.$message.success('生成成功')
    }).catch((error) => {
        //element组件,你可以直接使用alert查看
        this.$message.error('生成失败,请查看控制台错误')
    });
},

 2).涉及对dom的拖拽,流程图之类的(需复制dom,在复制的dom上进行处理)

downloadIMG() {
    //找到元素dom并复制一个临时元素(需要在id为flowWrap的div里面加上 ref="flowWrap")
    //我这里id为flowWrap,你需要替换为你的id
    const flow = this.$refs.flowWrap
    //svg转换canvas会导致svg无法拖动,使用临时元素
    const tmpFlow = flow.cloneNode(1)
    tmpFlow.style.background = '#000'
    flow.appendChild(tmpFlow)
    //调用changeToCanvas
    this.changeToCanvas(tmpFlow)
    html2canvas(tmpFlow, {
        taintTest: false,
        scale: window.devicePixelRatio < 2 ? 2 : window.devicePixelRatio, //scala属性解决生成的canvas模糊问题
    }).then((canvas) => {
        //调用base64ToFile
        let blob = this.base64ToFile(canvas.toDataURL('image/png'));
        let a = document.createElement('a');
        a.setAttribute('href', URL.createObjectURL(blob));
        a.setAttribute('download', new Date().getTime() + '.png');
        URL.revokeObjectURL(blob);
        a.click();
        a.remove();
        flow.removeChild(tmpFlow) // 移除临时tmpFlow
        //element组件,你可以直接使用alert查看
        this.$message.success('生成成功')
    }).catch((error) => {
        flow.removeChild(tmpFlow) // 移除临时tmpFlow
        //element组件,你可以直接使用alert查看
        this.$message.error('生成失败,请查看控制台错误')
    });
},

 三、效果图如下

猜你喜欢

转载自blog.csdn.net/weixin_43721856/article/details/128407846
今日推荐