vue-qr,canvas,JSZip,FileSaver前端隐式生成二维码合成海报打包压缩保存到本地

1,247 阅读2分钟

告别懒癌,对最近做的事情做一些记录。

vue-qr,canvas,JSZip,FileSaver前端隐式生成二维码合成海报打包压缩保存到本地

下载引入:

 import vueQr from 'vue-qr';
 import JSZip from 'jszip'
 import FileSaver from 'file-saver';
 //注意图片引入方式
 import posterBgImg from "@/assets/img/activation_base.jpg";
 import qrcodeLogo from "@/assets/img/logo.png";

注册组件,图片和一些数据:

components: {
        vueQr,
    },
    data:{
     posterSize: 1594/827,// 海报高宽比例
     qrCodeSize: {// 二维码与海报对应比例 =》 用于设置二维码在海报中的位置
      width: 300/827,
      height: 300/1594,
      left: 261/827,
      top: 612/827
     },
     poster: '',// 合成图片
     nowUrl:'',
     zip:'',
     imgZipList:'',
     countImg:0,
     batchNo:'',
     batchOrpage:''
     list: [],
    //注意图片引入方式
     posterBgImg,
     qrcodeLogo,
    },
    
    
    computed: {
    //手机端兼容的,根据屏幕宽度设置海报尺寸
    screenWidth(){
       let w = document.body.clientWidth || document.documentElement.clientWidth || 375;
       return w > 480 ? 480 : w ;
      }
    },
    

HTML部分,二维码生成:最重要的三个属性

ref:命名。方便以后this.refs[qr+refs['qr'+`{id}`].$el.src 拿到生成的二维码地址

text:就是二维码的信息啦,扫描后打开的网页。

size:尺寸

更多参数可以看文档根据需求选择不多赘述

我的项目里是批量生成的,最多支持一百张,没有太大压力。 并且全v-show=false隐藏也并不影响生成和下载功能。

//单张二维码
<vue-qr :ref="'qr'+scope.row.id" :text="scope.row.url" :size="300" v-show=false></vue-qr>


//批量二维码
 <el-table
            v-loading="listLoading"
            :data="List"
            element-loading-text="加载中..."
            border
            fit
            highlight-current-row
            :header-cell-style="{background:'#f4f0ec',color:'#000000'}"
            style="margin:20px 0;"
            v-show="false"
          >
            <el-table-column label="" min-width="60" align="center" >
                <template slot-scope="scope">
                    <vue-qr v-show="false"  :ref="'qr'+scope.row.id" :text="scope.row.url" :size="300"></vue-qr>
                </template>
            </el-table-column>
        </el-table>

直接贴代码吧。因为需求从拼接海报改成不拼接海报,所以没有做合并。

这部分是最终版本:

下载单张纯二维码——直接使用qrcode提供的方法dispatchEvent。

批量打包压缩下载纯二维码的代码——


        //下载单张纯二维码,是vue-qr提供的方法
        downLoadPureCode(id,batchNo,code){
       
            let a = document.createElement('a');
            // 下载图命名
            a.download = `二维码_${code}`;
            // 二维码url
            a.href = this.$refs['qr'+`${id}`].$el.src;
            //下载
            a.dispatchEvent(new MouseEvent('click'))
        },
        
        //压缩下载单页面全部纯二维码
        downLoadPagePureCode(){
            this.batchOrpage='page'
            //创建一个code文件夹,文件里里创建一个images文件,文件内容为空
            this.zip = new JSZip()
            this.imgZipList = this.zip.folder("images")
            //遍历数组拿
            this.list.forEach(item=>{
                // console.log('绘制',item.id)
                let a = document.createElement('a'+item.code);
                //拿到所有需要加入压缩包的二维码图片地址
                a.href = this.$refs['qr'+`${item.id}`].$el.src;
                // 打zip
                let that=this
                that.countImg++
                // console.log('push第'+that.countImg,a.href)
                let total= that.list.length
                //↓第一个参数是单张二维码图片的命名,第二个参数是二维码的base64,这里用replace把URL的前缀截掉仅保留纯base64编码,可以地址栏打开的那种
                that.imgZipList.file('二维码_'+item.code+'.png', a.href.replace(/^data:image\/(png|jpg);base64,/, ""), {base64: true});
                // console.log('push第'+that.countImg+'succ')
                if(that.countImg == total){
                    // console.log('finish')
                    //添加完下载
                  this.zip.generateAsync({type:"blob"}).then(function(content) {
                      // 使用file-saver保存下载zip文件,第二个参数是压缩包命名
                       FileSaver.saveAs(content, `第${that.queryWord.pageIndex}页_二维码.zip`);
                    });
                    this.countImg=0
                }
            })
        },
   

下面这部分是最初做的,相比之前就是在调用了combinedPoster方法拼接二维码和背景图,合成海报。 这个海报是用canvas绘制,同样不在页面展示也可以实现下载。

        //下载单张海报
        downLoadCode(id,batchNo,code){
            let a = document.createElement('a');
            a.href = this.$refs['qr'+`${id}`].$el.src;
            this.combinedPoster(a.href,batchNo,code,false)
        },
        //压缩下载页面全部海报
        downLoadPageCode(){
            this.batchOrpage='page'
            //创建一个code文件夹,文件里里创建一个images文件,文件内容为空
            this.zip = new JSZip()
            this.imgZipList = this.zip.folder("images")
            this.list.forEach(item=>{
                console.log('绘制',item.id)
                let a = document.createElement('a'+item.code);
                a.href = this.$refs['qr'+`${item.id}`].$el.src;
                this.combinedPoster(a.href,item.batchNo,item.code,true)
            })
        },

  
        //拼接二维码和背景图,合成海报的方法
        //参数依次是,二维码base64,内部批次号,内部编码,是否打zip包
        combinedPoster(_url,batchNo,code,ifzip){
            let that = this,
            posterBgImg = this.posterBgImg; //固定的背景地址
            // console.log("open draw: ", posterBgImg, _url)
            let base64 = '',
                canvas = document.createElement('canvas'),
                ctx = canvas.getContext("2d"),
                _w = this.screenWidth * 2, // 图片宽度
                _h = this.posterSize * _w, // 图片高度
                _qr_w = this.qrCodeSize.width * _w, // 二维码宽 = 比例 * 宽度
                _qr_h = this.qrCodeSize.height * _h, // 二维码高 = 比例 * 高度
                _qr_t = this.qrCodeSize.top * _w, // 二维码顶部距离 = 比例 * 宽度
                _qr_l = this.qrCodeSize.left * _w; // 二维码左侧距离 = 比例 * 宽度
            // 设置canvas宽高
            canvas.width = _w;
            canvas.height = _h;
            ctx.rect(0, 0, _w, _h);
            ctx.fillStyle = '#fff'; // 填充颜色
            ctx.fill();
            // 迭代生成: 第一层(底图)+ 第二层(二维码)
            // file:文件,size:[顶部距离,左侧距离,宽度,高度]
            let _list = [
                {
                    file: posterBgImg,
                    size: [0, 0, _w, _h]
                }, {
                    file: _url,
                    size: [_qr_l, _qr_t, _qr_w, _qr_h]
                }
            ];
            // 开始绘画
            let drawing = (_index) => {
                // 判断当前索引 =》 是否已绘制完毕
                if (_index < _list.length) {
                    // 等图片预加载后画图
                    let img = new Image(),
                        timeStamp = new Date().getTime();
                    // 防止跨域
                    img.setAttribute('crossOrigin', 'anonymous')
                    
                    img.src = _list[_index].file
                    img.onload = function() {
                        // 画图
                        ctx.drawImage(img, ..._list[_index].size)
                        // 递归_list
                        drawing(_index + 1)
                    }
                } else {
                    // 生成图片
                    base64 = canvas.toDataURL("image/png")
                    if (base64) {
                        // 赋值相应海报上
                        this.$set(that, 'poster', base64)
                        if(!ifzip){
                            //单张下载
                            if(this.poster){
                            let a = document.createElement("a");
                            a.setAttribute("download", "二维码"+'_'+code);
                            a.href = this.poster
                            a.click()
                          }else{
                          console.log("海报不存在,请重新生成!")
                          }
                        }else {
                            // 打包下载,打zip
                            that.countImg++
                            console.log('push第'+that.countImg)
                            let total=that.list.length
                            that.imgZipList.file('二维码_'+code+'.png', this.poster.replace(/^data:image\/(png|jpg);base64,/, ""), {base64: true});
                            console.log('push第'+that.countImg+'succ')
                            console.log(total)
                              if(that.countImg == total){
                                  console.log('finish')
                                //添加完下载
                                this.zip.generateAsync({type:"blob"}).then(function(content) {
                                    // 使用file-saver保存下载zip文件
                                    if(that.batchOrpage=='batch'){
                                        FileSaver.saveAs(content, `${that.batchNo}_二维码.zip`);
                                    }else{
                                        FileSaver.saveAs(content, `第${that.queryWord.pageIndex}页_二维码.zip`);
                                    }
                                });
                                this.countImg=0
                            }
                        }
                    }
                }
            }
            drawing(0)
        },