Bootstrap

dom-to-image.js 页面截图

重点:因为 dom-to-image.js 是根据 元素转换svg 进行截图的,所以如果元素有滚动条,他只能截图到 滚动条的顶部,不能截图到对应的滚动条位置


dom-to-image.js 引入

        1、下载

yarn add dom-to-image

        2、在 node_modules 文件夹中 找到 dom-to-image 文件夹里面的 dom-to-image.js 复制出来
        3、 页面引入

import domtoimage from 'dom-to-image.js';


dom-to-image.js 修改

  不修改也可以,我这边是因为使用了 阿里的oss,不能在后面加时间戳,所以修改

// 找到 文件中的 getAndEncode 方法,修改里面的 url

url += ((/\?/).test(url) ? "&" : "?")

dom-to-image.js 提供的方法

        1、domtoimage.toPng(…);将节点转化为png格式的图片
        2、domtoimage.toJpeg(…);将节点转化为jpg格式的图片
        3、domtoimage.toSvg(…);将节点转化为svg格式的图片,生成的图片的格式都是base64格式
        4、domtoimage.toBlob(…);将节点转化为二进制格式,这个可以直接将图片下载
        5、domtoimage.toPixelData(…);获取原始像素值,以Uint8Array 数组的形式返回,每4个数组元素表示一个像素点,即rgba值。这个方法也是挺实用的,可以用于WebGL中编写着色器颜色。

dom-to-image.js 方法中接受的参数

所有参数都可以不写,有默认的;
注意的是 `cacheBust`  参数,用于判断图片是否跨域

参数说明类型
filter  过滤器节点中默写不需要的节点;function
bgcolor 图片背景颜色;string
height, width图片宽高;string
style 传入节点的样式,可以是任何有效的样式;object
quality 图片的质量,也就是清晰度;一个介于 0 和 1 之间的数字,表示 JPEG 图像的图像质量(例如 0.92 => 92%)。默认为 1.0 (100%)number
cacheBust 将时间戳加入到图片的url中,相当于添加新的图片;Boolean
imagePlaceholder图片生成失败时,在图片上面的提示,相当于img标签的alt;string

 dom-to-image.js 方法使用

 domtoimage.toPng(需要截图的元素,{ cacheBust: true }).then(function (dataUrl) {
                    //console.log(dataUrl)
                })
                .catch(function (error) {
                    console.error('生成失败', error);
                });

dom-to-image.js bug修复

1、截图返回的图片,截不全

  •         发现页面截不全, toPng 截不全的 可替换 toBlob 进行截图
 domtoimage.toPng(toBlob,{ 
        filter: (el) => {
              // 过滤 VIDEO 标签
              return !(el.tagName === 'VIDEO')
            },
    }).then(function (toBlob) {
       console.log(toBlob)
    })

2、视频画面截图不到

  • 先把视频当前画面转成 canvas
  • 使用 canvasBox.getElementsByTagName('video') 获取的数组 不能使用 forEach 修改成 for
// 1 、先把视频当前画面转成 canvas

 const canvasBox = this.$refs.截图元素

 /* 视频 (新增一个canvas 标签到同级) */
        const canvasList = []
        const videoElList = []
        /* 找到元素下的所有 video 标签*/
        const videoList = canvasBox.getElementsByTagName('video')
        for (let i = 0; i < videoList.length; i++) {
            const el = videoList[i]
          if (el.tagName === 'VIDEO') {
          var canvas = document.createElement('canvas')
          var videoRatio = el.videoWidth / el.videoHeight;
          var width = el.offsetWidth, height = el.offsetHeight;
          var elementRatio = width / height;
          if(elementRatio > videoRatio) {
            width = height * videoRatio;
          } else {
            height = width / videoRatio;
          }
          canvas.width = width
          canvas.height = height
          canvas.className = 'juzhong'
          canvas.style.cssText = el.style.cssText
          const ctx = canvas.getContext('2d')
          ctx.drawImage(el, 0, 0, width, height)
          if (el.parentNode && el.parentNode.appendChild) {
            el.parentNode.appendChild(canvas)
          }
          canvasList.push(canvas)
        }
      }



// 2、开始截图,过滤视频标签

 domtoimage.toPng(canvasBox,{ 
        filter: (el) => {
              // 过滤 VIDEO 标签
              return !(el.tagName === 'VIDEO')
            },
    }).then(function (dataUrl) {
                    /* 视频 (删除 替换的 canvas 标签) */
                    canvasList.forEach(el => {
                         el.parentNode.removeChild(el)
                    })
                })

3、svg 使用了 svg-sprite-loader,导致截图内容不展示 svg

  • 按照下方代码执行
  • 使用 canvasBox.getElementsByTagName('video') 获取的数组 不能使用 forEach 修改成 for
// 1、在 svgIcon.vue 组件中,新增一个 svgName

  <svg :class="svgClass" aria-hidden="true" :svgName="svgName">
    <use :xlink:href="iconName" />
  </svg>


// 2、在截图元素中的 svg 插入内容

 const canvasBox = this.$refs.截图元素


  /* svg (找到 symbol 并移动到 svg 标签中) */
        const symbolList = []
        const svgList = canvasBox.getElementsByTagName('svg')
       for (let i = 0; i < svgList.length; i++) {
        const el = svgList[i]
        if (el.id === '__SVG_SPRITE_NODE__') {
          return
        }
        const svgName = el.getAttribute('svgName')
        const item = document.getElementById(`icon-${svgName}`)
        symbolList.push(item)
        el.appendChild(item)
      }


// 3、开始截图

domtoimage.toPng(canvasBox).then(function (dataUrl) {
                    /* svg (把获取的 symbol 移回去) */
            const svgPublic = document.getElementById('__SVG_SPRITE_NODE__')
            symbolList.forEach(el => {
              svgPublic.appendChild(el)
            })
})

4、阿里的oss 图片加载失败

  •   在复制出来的 dom-to-image.js 文件 搜索 getAndEncode 函数
// 找到 文件中的 getAndEncode 方法,修改里面的 url

url += ((/\?/).test(url) ? "&" : "?")

5、图片链接失效,访问不了,导致失败

  • 在复制出来的 dom-to-image.js 文件 搜索 newImage 函数
  • 找到  newImage 函数 里面的 inline 函数 的下方代码
// 原本代码

return new Promise(function (resolve, reject) {
                             element.onload = resolve;
                            element.onerror = reject
                            element.src = dataUrl;
                        });


// 修改后

return new Promise(function (resolve, reject) {
                             element.onload = resolve;
                             element.onerror = (e) => {
                              // 不管怎么样都执行 resolve
                              resolve()
                            };
                            element.src = dataUrl;
                        });

6、合成图片模糊

  • 在复制出来的 dom-to-image.js 文件 搜索 newCanvas 函数
// 原本代码

function newCanvas(domNode) {
            var canvas = document.createElement('canvas');
            canvas.width = options.width || util.width(domNode);
            canvas.height = options.height || util.height(domNode);

            if (options.bgcolor) {
                var ctx = canvas.getContext('2d');
                ctx.fillStyle = options.bgcolor;
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }
            return canvas;
        }


// 修改后

function newCanvas(domNode) {
            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');
            ctx.mozImageSmoothingEnabled = false;
            ctx.webkitImageSmoothingEnabled = false;
            ctx.msImageSmoothingEnabled = false;
            ctx.imageSmoothingEnabled = false;
            var scale = options.scale || 1; // 默认值1
            canvas.width = (options.width * scale) || util.width(domNode);
            canvas.height = (options.height * scale) || util.height(domNode);
            ctx.scale(scale, scale) // 添加了scale参数
            if (options.bgcolor) {
                ctx.fillStyle = options.bgcolor;
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }
            return canvas;
        }

 
// 使用 toBlob 作为例子
 domtoimage.toBlob(canvasBox, {
        width: 80,
        height:80,
        scale: 8
 })

;