注册

uniapp使用canvas实现二维码分享

实现使用canvas在小程序H5页面进行二维码分享 如下图效果 可以保存并扫码

e5909506f2b54c579d28562b6680036b~tplv-k3u1fbpfcp-zoom-in-crop-mark:3024:0:0:0.awebp?

总体思路:使用canvas进行绘制,为了节省时间固定部分采用背景图绘制 只有二维码以及展示图片及标题绘制,绘制完成后调用uni.canvasToTempFilePath将其转为图片展示

1.组件调用,使用ref调用组件内部相应的canvas绘制方法,传入相关参数 包括名称 路由 展示图片等。

 <SharePoster v-if='showposter' ref='poster' @close='close'/>

<script>
 import SharePoster from "@/components/share/shareposter.vue"
 export default {
   components: {
      SharePoster,
  },
  methods:{
      handleShare(item){
         this.showposter=true
         if(this.showvote){
           this.showvote=false
        }
         this.$nextTick(() => {
        this.$refs.poster.drawposter(item.name, `/pagesMore/voluntary/video/player?schoolId=${item.id}`,item.cover)
        })
      },
  }
</script>

2.组件模板放置canvas容器并赋予id以及宽度高度等,使用iscomplete控制是显示canvas还是显示最后调用uni.canvasToTempFilePath生成的图片

<div class="poster-wrapper" @click="closePoster($event)">
     <div class='poster-content'>
         <canvas canvas-id="qrcode"
           v-if="qrShow"
          :style="{opacity: 0, position: 'absolute', top: '-1000px'}"
         ></canvas>
         <canvas
           canvas-id="poster"
          :style="{ width: cansWidth + 'px', height: cansHeight + 'px' ,opacity: 0, }"
           v-if='!iscomplete'
         ></canvas>
         <image
           v-if="iscomplete"
          :style="{ width: cansWidth + 'px', height: cansHeight + 'px' }"
          :src="tempFilePath"
           @longpress="longpress"
         ></image>
     </div>
 </div>

3.data内放置相应配置参数

 data() {
     return {
         bgImg:'https://cdn.img.up678.com/ueditor/upload/image/20211130/1638258070231028289.png', //画布背景图片
         cansWidth:288, // 画布宽度
         cansHeight:410, // 画布高度
         projectImgWidth:223, // 中间展示图片宽度
         projectImgHeight:167, // 中间展示图片高度
         qrShow:true, // 二维码canvas
         qrData: null, // 二维码数据
         tempFilePath:'',// 生成图路径
         iscomplete:false, // 是否生成图片
    }
  },

4.在created生命周期内调用uni.createCanvasContext创建canvas实例 传入模板内canvas容器id

created(){
     this.ctx = uni.createCanvasContext('poster',this)
  },

5.调用对应方法,绘制分享作品

   // 绘制分享作品
     async drawposter(name='重庆最美高校景象',url,projectImg){
          uni.showLoading({
            title: "加载中...",
            mask: true
          })
          // 生成二维码
         await this.createQrcode(url)
         // 背景
         await this.drawWebImg({
           url: this.bgImg,
           x: 0, y: 0, width: this.cansWidth, height: this.cansHeight
        })
         // 展示图
         await this.drawWebImg({
           url: projectImg,
           x: 33, y: 90, width: this.projectImgWidth, height: this.projectImgHeight
        })
         await this.drawText({
           text: name,
           x: 15, y: 285, color: '#241D4A', size: 15, bold: true, center: true,
           shadowObj: {x: '0', y: '4', z: '4', color: 'rgba(173,77,0,0.22)'}
        })
         // 绘制二维码
         await this.drawQrcode()
         //转为图片
         this.tempFilePath = await this.saveCans()
         this.iscomplete = true
         uni.hideLoading()
    },

6.绘制图片方法,注意 this.ctx.drawImage方法第一个参数不能放网络图片 必须执行下载后绘制

  drawWebImg(conf) {
       return new Promise((resolve, reject) => {
         uni.downloadFile({
           url: conf.url,
           success: (res) => {
             this.ctx.drawImage(res.tempFilePath, conf.x, conf.y, conf.width?conf.width:"", conf.height?conf.height:"")
             this.ctx.draw(true, () => {
               resolve()
            })
          },
           fail: err => {
             reject(err)
          }
        })
      })
    },

7.绘制文本标题

 drawText(conf) {
       return new Promise((resolve, reject) => {
         this.ctx.restore()
         this.ctx.setFillStyle(conf.color)
         if(conf.bold) this.ctx.font = `normal bold ${conf.size}px sans-serif`
         this.ctx.setFontSize(conf.size)
         if(conf.shadowObj) {
           // this.ctx.shadowOffsetX = conf.shadowObj.x
           // this.ctx.shadowOffsetY = conf.shadowObj.y
           // this.ctx.shadowOffsetZ = conf.shadowObj.z
           // this.ctx.shadowColor = conf.shadowObj.color
        }
         let x = conf.x
         conf.text=this.fittingString(this.ctx,conf.text,280)
         if(conf.center) {
           let len = this.ctx.measureText(conf.text)
           x = this.cansWidth / 2 - len.width / 2 + 2
        }

         this.ctx.fillText(conf.text, x, conf.y)
         this.ctx.draw(true, () => {
           this.ctx.save()
           resolve()
        })
      })
    },
// 文本标题溢出隐藏处理
fittingString(_ctx, str, maxWidth) {
           let strWidth = _ctx.measureText(str).width;
           const ellipsis = '…';
           const ellipsisWidth = _ctx.measureText(ellipsis).width;
           if (strWidth <= maxWidth || maxWidth <= ellipsisWidth) {
             return str;
          } else {
             var len = str.length;
             while (strWidth >= maxWidth - ellipsisWidth && len-- > 0) {
               str = str.slice(0, len);
               strWidth = _ctx.measureText(str).width;
            }
             return str + ellipsis;
          }
        },

8.生成二维码

      createQrcode(qrcodeUrl) {
       // console.log(window.location.origin)
       const config={host:window.location.origin}
       return new Promise((resolve, reject) => {
         let url = `${config.host}${qrcodeUrl}`
         // if(url.indexOf('?') === -1) url = url + '?sh=1'
         // else url = url + '&sh=1'
         try{
           new qrCode({
             canvasId: 'qrcode',
             usingComponents: true,
             context: this,
             // correctLevel: 3,
             text: url,
             size: 130,
             cbResult: (res) => {
               this.qrShow = false
               this.qrData = res
               resolve()
            }
          })
        } catch (err) {
           reject(err)
        }
      })
    },

9.画二维码,this.qrData为生成的二维码资源

  drawQrcode(conf = { x: 185, y: 335, width: 100, height: 50}) {
return new Promise((resolve, reject) => {
this.ctx.drawImage(this.qrData, conf.x, conf.y, conf.width, conf.height)
this.ctx.draw(true, () => {
resolve()
})
})
},

10.将canvas绘制内容转为图片并显示,在H5平台下,tempFilePath 为 base64

// canvs => images
saveCans() {
return new Promise((resolve, reject) => {
uni.canvasToTempFilePath({
x:0,
y:0,
canvasId: 'poster',
success: (res) => {
resolve(res.tempFilePath)
},
fail: (err) => {
uni.hideLoading()
reject(err)
}
}, this)
})
},

11.组件全部代码

3fa1fa7be03694bd1acf5f2989b79828.png

作者:ArvinC
来源:juejin.cn/post/7041087990222815246

0 个评论

要回复文章请先登录注册