本文正在参加「 . 」

写在开头

最近在项目中遇到一个紧急的需求,大概要求就是前端接收后端接口信息后,需要独自生成带文字的二维码图片,并能批量打包成 .zip 包,提供下载。

为了在最快时间内完成需求,小编直接采用网上比较成熟的方案来做,具体过程如下:

  • qrcode:用于生成二维码。
  • html2canvas:用于绘制二维码与文字,并生成图片。
  • jszip:用于把文件生成 .zip 包。
  • file-saver:用于下载文件。

以上是我们需要使用到的 npm 包,可以先来把它们安装到项目中:

npm install qrcode html2canvas jszip file-saver -S

用qrcode生成二维码

qrcode 包是一个用于生成二维码的 javascript 库,它的使用也是非常简单,下面我们来具体看看如何生成一个二维码。

考虑到后面会生成多个二维码,所以把二维码生成单独抽离成一个组件,新建 Qrcode.vue 文件:

<template>
  <div class="qr">
    <img class="qr__img" :src="qrBase64" />
  </div>
</template>

<script>
import QRcode from 'qrcode'
export default {
  props: {
    qrContent: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      qrBase64: ''
    }
  },
  watch: {
    qrContent: {
      handler: function () {
        this.qrContent && this.init()
      },
      immediate: true
    }
  },
  methods: {
    async init () {
      this.qrBase64 = await this.createQR(this.qrContent)
    },
    // 生成二维码
    createQR (content, options) {
      return new Promise((resolve, reject) => {
        QRcode.toDataURL(content, options).then(url => {
          resolve(url)
        })
      })
    },
  }
}
</script>

<style scoped>
.qr{
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}
.qr__img{
  width: 100%;
  height: 200px;
}
</style>

App.vue 文件中引入使用:

<template>
<div class="box">
  <div v-for="(item, index) in qrData" :key="index" class="box-item">
    <Qrcode :qrContent="item.content" />
  </div>
</div>
</template>

<script>
import Qrcode from './components/Qrcode.vue';

export default {
  components: { Qrcode },
  data() {
    return {
      qrData: [
        { content: 'https://Admin.net' },
        { content: 'https://Admin.net/user/1908407919184670'},
        { content: 'https://www.baidu.com' },
      ]
    }
  },
}
</script>

<style scoped>
.box{
  margin: 20px;
  display: flex;
  flex-wrap: wrap;
}
.box-item{
  width: 200px;
  height: fit-content;
  border: 1px solid #eee;
  margin-right: 12px;
  margin-bottom: 12px;
}
</style>

纯前端生成二维码与文字的图片,并批量打包成压缩包下载

很简单我们就完成了第一步了。

纯前端生成二维码与文字的图片,并批量打包成压缩包下载

用html2canvas生成二维码与文字图片

第二步我们来给二维码添加一些文案描述,并让二维码和文案结合生成一张图片,这样才方便使用人员的传播。

html2canvas 包能快速帮我们完成这件事情,它的原理是利用了 canvas 技术来绘制图片与文字,再统一转成图片输出,具体过程我们接着往下来看。

App.vue 文件:

<template>
<div class="box">
  <div v-for="(item, index) in qrData" :key="index" class="box-item">
    <Qrcode :qrContent="item.content">
      <div v-if="item.type == 1" class="text">
        <div class="black">{{ item.date }}</div>
        <div class="black">{{ item.time }}</div>
      </div>
      <div v-if="item.type == 2" class="text">
        <div class="sub-title">课程内容</div>
        <div class="desc">{{ item.desc }}</div>
        <div class="sub-title">起止时间</div>
        <div class="black">{{ item.time }}</div>
      </div>
    </Qrcode>
  </div>
</div>
</template>

<script>
import Qrcode from './components/Qrcode.vue';

export default {
  components: { Qrcode },
  data() {
    return {
      qrData: [
        {
           content: 'https://Admin.net',
           type: 1,
           date: '2022年11月08号',
           time: '上午'
        },
        {
           content: 'https://Admin.net',
           type: 1,
           date: '2022年11月08号',
           time: '下午'
        },
        {
           content: 'https://Admin.net/user/1908407919184670',
           type: 2,
           time: '11/08 09:30 - 10:30',
           desc: '关于Vue3的知识点内容的学习,带你征服Vue3',
        },
        {
           content: 'https://www.baidu.com',
           type: 2,
           time: '11/08 02:30 - 16:30',
           desc: '学习React内容的课程',
        },
      ]
    }
  },
}
</script>

<style scoped>
...
.text{
  text-align: center;
  box-sizing: border-box;
  padding: 2px 30px 14px 30px;
  font-size: 12px;
  color: #333;
}
.text div{
  margin: 4px 0;
}
.black{
  color: #000;
  font-weight: bold;
}
.desc{
  margin-bottom: 16px;
}
.sub-title{
  color: #999;
}
</style>

为了方便不同文案描述的布局,我们以插槽 slot 的形式来插入文案描述。

Qrcode.vue 文件:

<template>
  <div class="qr" :id="uuid">
    <img class="qr__img" :src="qrBase64" @load="imgLoad" />
    <slot />
  </div>
</template>

<script>
import QRcode from 'qrcode'
import html2canvas from 'html2canvas'
export default {
  props: {
    qrContent: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      uuid: `qr_${this._uid}_code`, // 组件唯一ID
      qrBase64: ''
    }
  },
  watch: {
    qrContent: {
      handler: function () {
        this.qrContent && this.init()
      },
      immediate: true
    }
  },
  methods: {
    async init () {
      this.qrBase64 = await this.createQR(this.qrContent)
    },
    createQR (content, options) {
      return new Promise((resolve, reject) => {
        QRcode.toDataURL(content, options).then(url => {
          resolve(url)
        })
      })
    },
    createCanvas () {
      return new Promise((resolve, reject) => {
        const container = document.querySelector(`#${this.uuid}`)
        html2canvas(container).then(canvans => {
          const base64 = canvans.toDataURL('image/png')
          resolve(base64)
        })
      })
    },
    // 需要等图片加载完才能生成canvas
    async imgLoad () {
      const canvansBase64 = await this.createCanvas()
      console.log(canvansBase64) // 生成二维码+文案图片
    }
  }
}
</script>

这里有个注意点是需要等图片加载完,我们才能去初始化 html2canvas,否则二维码可能会是空白一片,可以监听 <img /> 标签的 load 事件来判断这个时机。

纯前端生成二维码与文字的图片,并批量打包成压缩包下载

用jszip生成压缩包

完成第二步后,我们就获取到每个图片的 base64 了。下面我们把这些信息收集起来,然后丢给 jszip 包就大功告成了。

这里我们采用 v-model 的形式来收集。

Qrcode.vue 文件:

...

export default {
  props: {
    ...
    value: {
      type: String,
      default: ''
    },  
  },
  methods: {
    ...,
    async imgLoad () {
      const canvansBase64 = await this.createCanvas()
      this.$emit('input', canvansBase64) // 把目标base64丢出去
    }
  }
  ...
}

App.vue 文件:

<template>
<div class="box">
  <div v-for="(item, index) in qrData" :key="index" class="box-item">
    <Qrcode :qrContent="item.content" v-model="item.url">
      ...
    </Qrcode>
  </div>
</div>
</template>

<script>
import Qrcode from './components/Qrcode.vue';
import JsZip from 'jszip'

export default {
  components: { Qrcode },
  data() {
    return {
      qrData: [
        {
           ...,
           url: ''
        },
        {
           ...,
           url: ''
        },
        {
           ...,
           url: ''
        },
        {
           ...,
           url: ''
        },
      ]
    }
  },
  methods: {
    pack() {
      const zip = new JsZip()
      const folder = zip.folder('创建文件夹')
      this.qrData.forEach((item, index) => {
        // 不需要base64的头部
        zip.file(`${index}_${item.type}.png`, item.url.split(',')[1], { base64: true })
      })
      zip.generateAsync({ type: 'blob' }).then(content => {
        console.log(content); // 压缩包
      })
    }
  }
}
</script>

纯前端生成二维码与文字的图片,并批量打包成压缩包下载

用file-saver完成下载

最后,我们使用 file-saver 来将压缩包下载下来。

App.vue 文件:

<template>
 <div>
   <button @click="download">一键下载所有码</button>
   <div class="box"> 
     ... 
   </div>
 </div>
</template>

<script>
import Qrcode from './components/Qrcode.vue';
import JsZip from 'jszip'
import { saveAs } from 'file-saver'

export default {
  methods: {
    download () {
      const QRRes = this.qrData.some(item => item.url === '')
      if (QRRes) {
         console.warn('当前存在一些二维码未生成完毕,这些二维码将无法下载')
      }
      this.pack()
    },
    pack() {
      const zip = new JsZip()
      const folder = zip.folder('创建文件夹')
      this.qrData.forEach((item, index) => {
        zip.file(`${index}_${item.type}.png`, item.url.split(',')[1], { base64: true })
      })
      zip.generateAsync({ type: 'blob' }).then(content => {
        saveAs(content, '我是新鲜出炉的压缩包唷')
      })
    }
  }
}

纯前端生成二维码与文字的图片,并批量打包成压缩包下载

可以看到效果整体还是不错的,开开心心收工。

纯前端生成二维码与文字的图片,并批量打包成压缩包下载





至此,本篇文章就写完啦,撒花撒花。

纯前端生成二维码与文字的图片,并批量打包成压缩包下载

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。

adminjs.Cn 工作生活学习必备

声明:本文仅供个人学习使用,来源于互联网,本文有改动,本文遵循[BY-NC-SA]协议, 如有侵犯您的权益,请联系本站,本站将在第一时间删除。谢谢你

原文地址:纯前端生成二维码与文字的图片,并批量打包成压缩包下载