案例1

实现背景:

  • 海报的尺寸依据图片大小来的,宽度百分百,高度同比例缩放,图上笼罩二维码
  • 如果没有设置海报图片,应用别的图片,在底部增加一个底部的固定图片,和二维码,和图片的左上角笼罩log图
    难点:
  • 因为是应用canvas渲染的图片,然而图片的尺寸不是固定,也就是canvas的尺寸不是固定(解决:在内部先获取图片的尺寸,传进这个组件中)
  • h5是渲染失常的,微信小程序图片渲染不进去(解决:微信不反对canvas间接渲染网络图片,所以须要先缓存到本地)
<template>  <view class="poster-box" ref="posterBox" @click="hidePoster">    <canvas      :style="{        width: posterOptions.poster.canvasWidth + 'px',        height: posterOptions.poster.canvasHeight + 'px',      }"      canvas-id="myCanvas"    ></canvas>    <!-- #ifdef MP  -->    <image      :src="base64"      class="poster-image"      :draggable="false"      show-menu-by-longpress="true"    ></image>    <!-- #endif -->    <!-- #ifdef H5 -->    <image class="poster-image" :src="base64" :draggable="false"></image>    <!-- #endif -->  </view></template><script>import Qr from '@/utils/wxqrcode'export default {  name: 'poster_canvas',  data() {    return {      base64: '', // 海报绘制成图片以便保留    }  },  props: {    //图片地址    posterOptions: {      type: Object,      require: true,    },  },  mounted() {    this.$nextTick(() => {      this.imgToCanvas()    })  },  methods: {    async imgToCanvas() {      let that = this            let canvasHeight = this.posterOptions.isHavePosterImg        ? this.posterOptions.poster.canvasHeight        : this.posterOptions.poster.canvasHeight -          this.posterOptions.buttonOption.h      // 渲染大图      let ctx = uni.createCanvasContext('myCanvas', that)      console.log(11111,this.posterOptions)      ctx.drawImage(        this.posterOptions.poster.url,        0,        0,        this.posterOptions.poster.canvasWidth,        canvasHeight      )      if (!this.posterOptions.isHavePosterImg) {        //渲染底部的图片        ctx.drawImage(          this.posterOptions.buttonOption.bottomUrl,          this.posterOptions.buttonOption.x,          this.posterOptions.buttonOption.y,          this.posterOptions.buttonOption.w,          this.posterOptions.buttonOption.h        )      }      // 渲染二维码      if (this.posterOptions.QrOption.isWeChatMiniApp) {        ctx.drawImage(          this.posterOptions.QrOption.QrUrl,          this.posterOptions.QrOption.x,          this.posterOptions.QrOption.y,          this.posterOptions.QrOption.w,          this.posterOptions.QrOption.h        )      } else {        //一般二维码        let qrCodeImg = Qr.createQrCodeImg(this.posterOptions.QrOption.QrUrl, {          size: parseInt(300),        })        ctx.drawImage(          qrCodeImg,          this.posterOptions.QrOption.x,          this.posterOptions.QrOption.y,          this.posterOptions.QrOption.w,          this.posterOptions.QrOption.h        )      }      if (!this.posterOptions.isHavePosterImg) {        // 渲染log 和文字        ctx.drawImage(          this.posterOptions.logOption.logUrl,          this.posterOptions.logOption.x,          this.posterOptions.logOption.y,          this.posterOptions.logOption.w,          this.posterOptions.logOption.h        )        ctx.fillStyle = this.posterOptions.textOption.color        ctx.setFontSize(22)        ctx.font = 'bold arial'        ctx.fillText(          this.posterOptions.textOption.text,          this.posterOptions.textOption.x,          this.posterOptions.textOption.y        )      }      ctx.save() //保留      ctx.draw() //绘制      // 不加提早的话,base64有时候会赋予undefined      // 把以后画布指定区域的内容导出生成指定大小的图片,并返回文件门路      setTimeout(() => {        uni.canvasToTempFilePath(          {            canvasId: "myCanvas",            fileType: "jpg",            width:that.posterOptions.poster.canvasWidth,            height:that.posterOptions.poster.canvasHeight,            destWidth:that.posterOptions.poster.canvasWidth,            destHeight:that.posterOptions.poster.canvasHeight,            success: function (res) {              that.base64 = res.tempFilePath;            },            fail: function (error) {              console.log(error, "谬误");            },          },that        );      }, 500);    },    hidePoster() {      // #ifdef H5      this.$parent.$parent.hidePoster()      // #endif      // #ifndef H5      this.$parent.hidePoster()      // #endif    },  },}</script><style lang="scss" scoped>.poster-box {  position: fixed;  top: 0;  z-index: 999;  background-color: rgba(0, 0, 0, 0.8);  width: 100%;  height: 100%;  display: flex;  align-items: center;  justify-content: center;}.poster-image {  position: absolute;  top: 0;  left: 0;  z-index: 1000;  width: 100%;  height: 100%;  opacity: 0;}</style>

应用

<template>  <view    class="contentBgc"    :style="{ backgroundColor: detailObj.backgroundColor || defaultBgc }"  >    <image      class="width-100"      :src="detailObj.activityDetailHeadImg"      mode="widthFix"    />    <view v-for="item in detailObj.plateDtoList" :key="item.id">      <TopicThree v-if="detailObj.currentTemplate == 3" :itemObj="item" />      <TopicTwo v-if="detailObj.currentTemplate == 2" :itemObj="item" />      <TopicOne v-if="detailObj.currentTemplate == 1" :itemObj="item" />    </view>    <generateaposter v-if="isGetOk" @pChangeType="showPoster" />    <SharePoster v-if="posterShow" :posterOptions="posterOptions"></SharePoster>  </view></template><script>import TopicOne from './components/topicOne.vue'import TopicTwo from './components/topicTwo.vue'import TopicThree from './components/topicThree.vue'import { getSpecialTopicData } from '@/api/specialTopic.js'// #ifdef H5import { getShopWxConfig, share } from '@/utils/wxShare.js'// #endifimport mixinWxshare from '@/utils/wxShareTimeline.js' //微信分享朋友圈import generateaposter from '@/components/gpage/generateaposter.vue'import SharePoster from './components/sharePoster.vue'import { cmsWxacodeGetwxacode } from '@/api/product'export default {  mixins: [mixinWxshare],  components: {    TopicOne,    TopicTwo,    TopicThree,    generateaposter,    SharePoster,  },  onLoad(options) {    this.activityUniqueCode = options.activityUniqueCode    this.initData()  },  data() {    return {      defaultBgc: '#fff', //默认背景色      share: this.$utils.getImgUrl('/static/mcShopImage/share.png'), //分享      detailObj: {},      activityUniqueCode: '',      posterShow: false,      isGetOk: false,      posterOptions: {        isHavePosterImg: false, //用户是否上传了分享海报的图片        activityName: '',        textOption: {          text: '',          x: 0, // X轴坐标          y: 20, // Y轴坐标          color: '#9c6d06',        },        poster: {          url:            'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fci.xiaohongshu.com%2F0429f29e-85f3-5826-9608-946fc1ee103a%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fci.xiaohongshu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664356680&t=349aa739d52cd748c50b3afd89da2ba2',          canvasWidth: 0,          canvasHeight: 0,        },        QrOption: {          QrUrl: '', // 二维码链接          x: 20, // 图片X轴坐标          y: 20, // 图片Y轴坐标          w: 90, // 图片宽度          h: 90, // 图片高度          isWeChatMiniApp: false, // 是否是微信小程序二维码 true是微信小程序, false 不是微信小程序        },        logOption: {          //log          logUrl:            'https://jemsfile.mochouu.com/provider/91949676/20220831/1661926456418.png',          x: 15, // 图片X轴坐标          y: 15, // 图片Y轴坐标          w: 120, // 图片宽度          h: 45, // 图片高度        },        buttonOption: {          //底部的图片          bottomUrl:            'https://jemsfile.mochouu.com/provider/91949676/20220831/1661930915954.png',          x: 0, // 图片X轴坐标          y: 20, // 图片Y轴坐标          w: 100, // 图片宽度          h: 100, // 图片高度        },      },      screenWidth: 0,    }  },  mounted() {},  // #ifndef H5  /* 微信小程序分享 */  onShareAppMessage: function(res) {    // console.log('分享的userCode:'+this.userInfo.userCode)    let userInfo = this.$utils.getStorageSync('userInfo')    let routes = getCurrentPages() // 获取以后关上过的页面路由数组    let curParam =      routes[routes.length - 1].options ||      routes[routes.length - 1].$route.query //获取路由参数    if (userInfo) {      curParam.userCode = userInfo.userCode    }    let a = this.$utils.pageliks(curParam, routes)    let obj = {      title: this.detailObj.shareTitle || this.detailObj.shareContent || '',      desc:this.detailObj.shareContent||'',      path: a,      imageUrl: this.detailObj.shareImg || this.detailObj.verticalImgUrl || '',    }    return obj  },  // #endif  methods: {    hidePoster() {      this.posterShow = false    },    getWxCode() {      uni.showLoading({        title: '加载中',      })      let that = this      this.isGetOk = false      let routes = getCurrentPages() // 获取以后关上过的页面路由数组      let curRoute = routes[routes.length - 1].route //获取以后页面路由      let curParam = routes[routes.length - 1].options //获取路由参数      let obj = {}      obj.curRoute = curRoute      obj.curParam = curParam      // 拼接参数      let str = ''      for (let key in obj.curParam) {        str += '&' + key + '=' + obj.curParam[key]      }      str = str ? '?' + str.substr(1, str.length) : ''      let data = {        page: '/' + obj.curRoute + str,      }      cmsWxacodeGetwxacode(data).then((res) => {        uni.hideLoading()        if (res.code === 1000) {          this.downImg(res.data, that.posterOptions.QrOption, 'QrUrl')          that.$set(that.posterOptions.QrOption, 'isWeChatMiniApp', true)          that.isGetOk = true        }      })    },    // 显示分享海报    showPoster() {      this.posterShow = true    },    /* 任务分配 */    assignTasks(data) {      /* 设置头部的title */      uni.setNavigationBarTitle({        title: data.activityName,      })      // 初始化分享朋友圈      // #ifndef H5      this.initWxShareData(        this.detailObj.shareTitle || this.detailObj.shareContent,        this.detailObj.shareImg || this.detailObj.verticalImgUrl      )      // #endif      // #ifdef H5      switch (uni.getSystemInfoSync().platform) {        case 'android':          this.fx(1)          break        case 'ios':          this.fx(2)          break      }      // #endif    },    /* 初始化数据 */    initData() {      let that = this      getSpecialTopicData(this.activityUniqueCode).then((res) => {        if (res.code == 1000) {          const { plateDtoList, ...rest } = res.data          let filterData = plateDtoList.map((it) => {            const { productJson, ...re } = it            let objArr = JSON.parse(productJson)            return {              productJson: objArr||[],              ...re,            }          })          this.detailObj = { plateDtoList: filterData, ...rest }          this.assignTasks(this.detailObj)          // #ifdef MP          uni.getSystemInfo({            success: (res) => {              that.screenWidth = res.windowWidth            },          })          this.getWxCode()          // #endif          // #ifdef H5          that.screenWidth = document.documentElement.clientWidth          this.posterOptions.QrOption.QrUrl = window.location.href          this.isGetOk = true          // #endif          // 判断是否设置了分享海报的图片          let isHaveImg = this.detailObj.posterImg ? true : false          if(!isHaveImg){            this.downImg(that.posterOptions.logOption.logUrl, that.posterOptions.logOption, 'logUrl')            this.downImg(that.posterOptions.buttonOption.bottomUrl, that.posterOptions.buttonOption, 'bottomUrl')          }          this.$set(this.posterOptions, 'isHavePosterImg', isHaveImg)          this.$set(            this.posterOptions.textOption,            'text',            this.detailObj.activityName          )          // 设置img图片和canvas大小          let posterImg = this.detailObj.posterImg            ? this.detailObj.posterImg            : this.detailObj.activityDetailHeadImg          // 设置大图的url          this.downImg(posterImg, this.posterOptions.poster, 'url')          uni.getImageInfo({            src: posterImg,            success(res) {              let imgW = res.width //图片宽度              let imgH = res.height //图片高度              let per = imgW / that.screenWidth              that.$set(                that.posterOptions.poster,                'canvasWidth',                that.screenWidth              )              // 是否设置分享海报              let canvasHeight = isHaveImg                ? imgH / per                : imgH / per + that.posterOptions.buttonOption.h              that.$set(that.posterOptions.poster, 'canvasHeight', canvasHeight)              // 设置二维码地位              let codeX = isHaveImg ? that.screenWidth - 95 : 5              that.$set(that.posterOptions.QrOption, 'x', codeX)              let codeY = isHaveImg ? imgH / per - 95 : canvasHeight - 95              that.$set(that.posterOptions.QrOption, 'y', codeY)              if (!isHaveImg) {                // 如果没有设置分享海报                that.$set(                  that.posterOptions.buttonOption,                  'w',                  that.screenWidth                )                that.$set(that.posterOptions.buttonOption, 'y', imgH / per)                that.$set(that.posterOptions.textOption, 'x', codeX + 120)                that.$set(that.posterOptions.textOption, 'y', codeY + 40)              }            },          })        }      })    },    // 将网络图片缓存到本地    downImg(img, obj, name) {      let that = this      uni.downloadFile({        url: img,        success: (res) => {          that.$set(obj, name, res.tempFilePath)        },      })    },    // 分享办法    fx(val) {      let url = window.location.href      // 获取usercode      let urls      let userInfo = this.$utils.getStorageSync('userInfo')      let routes = getCurrentPages() // 获取以后关上过的页面路由数组      let curParam =        routes[routes.length - 1].options ||        routes[routes.length - 1].$route.query //获取路由参数      if (userInfo) {        curParam.userCode = userInfo.userCode      }      let a = this.$utils.pageliks(curParam, routes)      let b = window.location.origin      if (userInfo) {        urls = `${b}${a}`      } else {        urls = url      }      let data = {        url: url,      }      let shares = {        title: this.detailObj.shareTitle || this.$config.serviceProvider,        link: urls,        desc:this.detailObj.shareContent||'',        imgUrl: this.detailObj.shareImg || '',      }      if (val == 1) {        getShopWxConfig(data, shares, val)      } else {        share(shares)      }    },  },}</script><style lang="scss" scoped>.width-100 {  width: 100%;}.contentBgc {  min-height: 100vh;  width: 100vw;  padding-bottom: 20rpx;}</style>