ly2011 / blog

前端学习笔记
https://ly2011.github.io/blog
122 stars 12 forks source link

借助html2canvas实现网页保存为图片 #165

Open ly2011 opened 5 years ago

ly2011 commented 5 years ago

借助html2canvas实现网页保存为图片

html2canvas 能够实现在前端直接对页面进行截屏。其实现思路是html2canvas脚本将页面元素渲染为canvas,通过读取DOM并将不同的样式应用到这些元素上实现。它不需要服务端的操作,只在前端即可完成。

一. 在项目中的使用

1. 安装html2canvas

npm install --save html2canvas

2. 在项目中使用

 // 在需要使用的页面中先引入html2canvas
 import html2canvas from 'html2canvas'

然后在页面中使用,如下:

在template模板中,设置要生成图片的内容,本文中要生成图片的是ref="capture"的div,然后将生成的canvas图片展示在ref="addImage"的div中

<template>
  <!-- 本文中要生成图片的是ref="capture"的div,然后将生成的canvas图片展示在ref="addImage"的div中 -->
  <div class="content" ref="addImage">
    <div ref="capture" class="image-content">
      <div class="parent">
        <img src="https://user-gold-cdn.xitu.io/2018/12/18/167c06ce8cf413d1?w=476&h=260&f=webp&s=11552">
      </div>
      <div class="parent">
        <img src="https://user-gold-cdn.xitu.io/2018/12/18/167c06ce8d058da5?w=140&h=140&f=png&s=563">
      </div>
      <div class="parent">
        <img src="https://user-gold-cdn.xitu.io/2018/12/18/167c06ce8da5216c?w=160&h=280&f=webp&s=10926">
      </div>
      <div class="parent">
        <img src="https://img.alicdn.com/tps/i4/TB1hn3NMwHqK1RjSZFgSuu7JXXa.jpg_620x10000q100.jpg_.webp" alt>
      </div>
    </div>
    <button @click="generatorImage" class="img-btn">生成图片</button>
  </div>
</template>

然后在js文件中,generatorImage方法实现html到图片的转换,此时即可看到页面尾部已经添加了生成的图片内容,也可以对图片转为base64编码并下载到本地。

generatorImage () {
  html2canvas(this.$refs.capture, { useCORS: true, backgroundColor: null }).then(canvas => {
    this.$refs.addImage.append(canvas)

    // 通过a标签下载到本地
    let link = document.createElement('a')
    link.href = canvas.toDataURL()
    link.setAttribute('download', '图片canvas.png')
    link.style.display = 'none'
    document.body.appendChild(link)
    link.click()
  })
}

二. html2canvas存在跨域资源无法加载

如果要生成图片的dom元素中,包含有跨域资源,比如img标签中的跨域图片,通过上述方法生成的图片中,img的内容是空白的,无法生成,这是因为canvas对于图片资源的同源限制。

解决办法: html2canvas可以设置配置项,来实现图片的加载

1. allowTaint 设置成true,即可实现图片的展示(但是会导致无发下载)

allowTaint 为 true是允许canvas被污染,一旦画布污染,就无法读取其数据,不能使用画布的 toBolb(), toDataURL()getImageData() 方法,否则会出错.

如果我们只是展示在页面上,不通过js转为文件下载到本地(下载需要调用canvas.toDataURL()方法),则可以使用该方法。(页面中右键可以将这张图片完好的保存到本地)

2. 通过服务器端设置CORS

解决跨域最常用的方法是跨域资源共享,我们将图片服务器的 response header 设置

access-control-allow-origin: *

即可解决跨域图片的访问,同时,配合html2canvas的配置项useCORS: true,即可实现canvas图片的转化和下载。

完整demo:

<template>
  <!-- 本文中要生成图片的是ref="capture"的div,然后将生成的canvas图片展示在ref="addImage"的div中 -->
  <div class="content" ref="addImage">
    <div ref="capture" class="image-content">
      <div class="parent">
        <img src="https://user-gold-cdn.xitu.io/2018/12/18/167c06ce8cf413d1?w=476&h=260&f=webp&s=11552">
      </div>
      <div class="parent">
        <img src="https://user-gold-cdn.xitu.io/2018/12/18/167c06ce8d058da5?w=140&h=140&f=png&s=563">
      </div>
      <div class="parent">
        <img src="https://user-gold-cdn.xitu.io/2018/12/18/167c06ce8da5216c?w=160&h=280&f=webp&s=10926">
      </div>
      <div class="parent">
        <img src="https://img.alicdn.com/tps/i4/TB1hn3NMwHqK1RjSZFgSuu7JXXa.jpg_620x10000q100.jpg_.webp" alt>
      </div>
    </div>
    <el-button @click="generatorImage" type="primary" class="img-btn">生成图片</el-button>
  </div>
</template>

<script>
import html2canvas from 'html2canvas'
export default {
  methods: {
    generatorImage () {
      html2canvas(this.$refs.capture, { useCORS: true, backgroundColor: null }).then(canvas => {
        this.$refs.addImage.append(canvas)

        // 通过a标签下载到本地
        let link = document.createElement('a')
        link.href = canvas.toDataURL()
        link.setAttribute('download', '图片canvas.png')
        link.style.display = 'none'
        document.body.appendChild(link)
        link.click()
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.content {
  .image-content {
    display: flex;
    flex-wrap: wrap;
    max-width: 1200px;
    padding: 20px 30px;
  }
  .parent {
    flex: 1;
  }
}
</style>

常见BUG

在配置项里配置 backgroundColor: null 即可。

这是最常见的一个bug,就是这个插件无法生成跨域了的图片

先让生成的图片隐藏,等生成好以后再展示

1). 生成的图片模糊 2). 有跨域图片导致生成的图片不完整