vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)

遇到的问题

在项目开发中有一个需求,用户上传一个时间线的数据,通过选择不同的模板,将时间线数据可视化。用户保存这个文件时,将模板预览图截取作为文件的封面。

实现的思路

最终的结果就是把相应的DOM转换成一张图片传回后台。关键难点在于如何把DOM转换成图片。然鹅,最难搞定的那部分已经有了一个较为成熟的框架html2canvas。项目时间比较急迫,先使用第三方插件,自己封装canvas方法来截图的方案,后续再尝试一下。

  • 获取iframe的dom结构
  • 将获取到的dom直接传给html2canvas,转换canvas
  • 调用toDataURL将canvas转换成图片base64格式
html

vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第1张图片

页面展示

vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第2张图片

实现步骤
  • 获取iframe的dom结构
const iframeHtml = this.$refs.timeLineDom.contentWindow // 获取iframe内容
const iframeBody = iframeHtml.document.getElementsByTagName('body')[0]
  • 将dom转换成canvas,并转换成base64
    imgBase64就是截取到的图片,格式是base64
 html2canvas(iframeBody).then(canvas => {
   // 转成图片,生成图片地址
   imgBase64 = canvas.toDataURL('image/png')
   if (imgBase64) {
     resolve(imgBase64)
   } else {
     reject(new Error('图片转换出错')
   }
 })

因为是保存文件时,执行的转换操作。我们要在图片成功转换成功后再进行保存操作。所以代码要稍微改造一下:

handleSaveImg () {
 let imgBase64 = null
   var iframeHtml = this.$refs.timeLineDom.contentWindow // 获取iframe内容
   const iframeBody = iframeHtml.document.getElementsByTagName('body')[0]
   return new Promise(function (resolve, reject) {
     html2canvas(iframeBody).then(canvas => {
       // 转成图片,生成图片地址
       imgBase64 = canvas.toDataURL('image/png')
       if (imgBase64) {
         resolve(imgBase64)
       } else {
         reject(new Error(this.globleMessage.errorImgTransform))
       }
     })
   })
 },

搞定!看一下效果
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第3张图片
。。。显然这有违初衷,图片太长导致压缩得根本看不出什么

再过一遍需求,我们最理想的效果是:预览窗口显示什么样子,封面的图片就应该是什么样子。

我们还需要做一些处理,即,拿到iframe里面模板滚动的距离,通过计算截取与预览窗口一样视图区域。

  • 获取iframe滚动的距离
const iframeScrollY = iframeHtml.document.documentElement.scrollTop
const iframeScrollX = iframeHtml.document.documentElement.scrollLeft
  • 将滚动的距离和要截取的宽高传给html2canvas
html2canvas(iframeBody, {
  allowTaint: true,
   useCORS: true,
   width: 812, // TODO 截屏按照1920*1080分辨率下的预览窗口宽高
   height: 661,
   x: iframeScrollX,
   y: iframeScrollY
 })

看一下效果
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第4张图片
这样功能算是完成了。看看其他模板的效果:
预览图:
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第5张图片
封面:
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第6张图片
预览图2:
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第7张图片
封面2:
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第8张图片

预览图3:
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第9张图片
封面3:
vue 项目使用html2canvas插件进行截屏(截取iframe页面的一部分)_第10张图片

最终代码

handleSaveImg () {
 let imgBase64 = null
 var iframeHtml = this.$refs.timeLineDom.contentWindow // 获取iframe内容
 const iframeBody = iframeHtml.document.getElementsByTagName('body')[0]
 const iframeScrollY = iframeHtml.document.documentElement.scrollTop
 const iframeScrollX = iframeHtml.document.documentElement.scrollLeft
 return new Promise((resolve, reject) => {
   html2canvas(iframeBody, {
     allowTaint: true,
     useCORS: true,
     width: 812, // TODO 截屏按照1920*1080分辨率下的预览窗口宽高
     height: 661,
     x: iframeScrollX,
     y: iframeScrollY
   }).then(canvas => {
     // 转成图片,生成图片地址
     imgBase64 = canvas.toDataURL('image/png')
     if (imgBase64) {
       resolve(imgBase64)
     } else {
       reject(new Error(this.globleMessage.errorImgTransform))
     }
   })
 })
},

你可能感兴趣的:(前端杂记,vue.js,canvas,html5,chrome)