uni-app刮獎

uni-app的刮獎效果,要注意的點:

1.小程序的canvas層級問題(可用cover-view規避)

2.不能操作dom

以下是uni-app刮獎效果的代碼:

<template>
  <!-- 刮獎 -->
  <view v-else class="scratch">
    <view class="box">
      <!-- 刮獎結果圖片 -->
      <image :src="domain+prize_img" class="img"></image>
      <!-- 刮獎canvas容器 -->
      <canvas
        class="canvas-box"
        canvas-id="canvas-id"
        :disable-scroll="true"
        @touchstart="touchStart"
        @touchmove="touchMove"
        @touchend="touchEnd"
      ></canvas>
      <!-- 刮獎前提示消息,開始刮獎後隱藏 -->
      <cover-view class="tip" v-if="!toDraw">
        <cover-view class="text">
          <cover-view class="text-tip">你還有</cover-view>
          <cover-view class="light">1</cover-view>
          <cover-view class="text-tip">次刮獎機會</cover-view>
        </cover-view>
        <!-- 開始刮獎按鈕 -->
        <cover-view class="btn" @tap="scratchStart()">
          <cover-image :src="domain + '/front/img/scratch-btn-bg.png'" class="btn-img"></cover-image>
          <cover-view class="text">立即刮獎</cover-view>
        </cover-view>
      </cover-view>
      <!-- 如果後端沒有不中獎的圖,則不中獎時默認顯示 -->
      <view v-if="hasDraw" class="award-box">
        <text class="text">謝謝參與</text>
      </view>
    </view>
  </view>
</template>

<script>
import Scratch from '@/utils/scratch.js'
export default {
  data () {
    return {
      domain: getApp().globalData.baseUrl, // 服務器域名
      toDraw: false, // 是否開始刮獎
      showResult: false, // 是否顯示抽獎結果
      isWin: true, // 是否中獎
      scratchWidth: 350, // 繪製刮獎範圍寬
      scratchHeight: 150, // 繪製刮獎範圍高
      scratchSize: 10, // 觸手大小
      scratchScale: 0.25, // 需刮開百分比
      prize_img: '', // 中獎圖片
      isScratching: false // 是否正在刮獎,
    }
  },
  methods: {
    initCanvas () {
      // 刮獎初始化信息必須在onReady後,不然h5不支持(小程序可在onLoad執行)
      new Scratch(this, {
        canvasId: 'canvas-id',
        width: this.scratchWidth,
        height: this.scratchHeight,
        size: this.scratchSize,
        scale: this.scratchScale
      })
    },
    // 請求刮獎結果
    doPrizeScratchTicketFun () {
      if (this.isScratching) return false
      this.isScratching = true
      // 請求服務器刮獎結果信息
      this.$api.luckDraw
        .doPrizeScratchTicket()
        .then(res => {
          this.prize_img = res.luckyPrize.prize_img
          this.luckyPrize = res.luckyPrize
          this.isWin = true
          if (this.luckyPrize.is_winning === 2) this.isWin = false
          this.isScratching = false
        })
        .catch(() => {
          this.isScratching = false
        })
    },
    // 點擊按鈕開始刮獎
    scratchStart () {
      this.toDraw = true
      this.initCanvas()
      this.doPrizeScratchTicketFun()
    }
  }
}
</script>

<style lang="scss">
.scratch {
  width: 670upx;
  height: 320upx;
  background: url($baseImgUrl+"luck-draw-guajiang.png") no-repeat;
  background-size: contain;
  margin: 366upx auto 80upx;
  padding: 29upx 25upx 21upx;
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  .box {
    width: 100%;
    height: 100%;
    background: $subGrey;
    border-radius: 20upx;
    position: relative;
    overflow: hidden;
    .img {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
    }
    .canvas-box {
      position: absolute;
      top: 0;
      left: 0;
      width: 100.5%;
      height: 100%;
      border-radius: 20upx;
      overflow: hidden;
    }
    .tip {
      position: absolute;
      left: 0;
      right: 0;
      width: 100%;
      height: 100%;
      z-index: 999;
      text-align: center;
      .text {
        font-size: 30upx;
        font-weight: bold;
        color: $darkTextColor;
        margin-top: 69upx;
        .text-tip {
          display: inline-block;
          vertical-align: middle;
        }
        .light {
          color: $red;
          display: inline-block;
          vertical-align: middle;
          margin: 0 6upx !important;
        }
      }
      .btn {
        width: 360upx;
        height: 82upx;
        border: none;
        border-radius: 41upx;
        margin: 59upx auto 0;
        position: relative;
        background: none;
        .btn-img {
          border: none;
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
        }
        .text {
          display: inline;
          position: absolute;
          text-align: center;
          color: #fff;
          font-size: 30upx;
          font-weight: bold;
          margin: 0;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
        }
      }
    }
    .award-box {
      width: 100%;
      height: 100%;
      border-radius: 20upx;
      text-align: center;
      line-height: 270upx;
      background: $yellow;
      .text {
        font-size: 40upx;
        font-weight: bold;
        color: $darkTextColor;
      }
    }
  }
}
</style>
<!-- scratch.js文件的內容(參考scratch.js) -->
class Scratch {
  constructor (page, opts) {
    opts = opts || {}
    this.page = page
    this.canvasId = opts.canvasId || 'canvas'
    this.width = opts.width || 340
    this.height = opts.height || 150
    this.maskColor = opts.maskColor || '#D2D2D2'
    this.size = opts.size || 10
    this.r = this.size * 2
    this.area = this.r * this.r
    this.scale = opts.scale || 0.3
    this.totalArea = this.width * this.height

    this.init()
  }

  init () {
    this.show = false
    this.clearPoints = []
    this.ctx = uni.createCanvasContext(this.canvasId)
    this.drawMask()
    this.bindTouch()
  }

  drawMask () {
    this.ctx.setFillStyle(this.maskColor)
    this.ctx.fillRect(0, 0, this.width, this.height)
    this.ctx.draw()
  }

  bindTouch () {
    this.page.touchStart = (e) => {
      this.eraser(e, true)
    }
    this.page.touchMove = (e) => {
      this.eraser(e, false)
    }
    this.page.touchEnd = (e) => {
      if (this.show) {
        this.ctx.clearRect(0, 0, this.width, this.height)
        this.ctx.draw()
      }
    }
  }

  eraser (e, bool) {
    const len = this.clearPoints.length
    let count = 0
    const x = e.touches[0].x; const y = e.touches[0].y
    const x1 = x - this.size
    const y1 = y - this.size
    if (bool) {
      this.clearPoints.push({
        x1: x1,
        y1: y1,
        x2: x1 + this.r,
        y2: y1 + this.r
      })
    }
    for (const item of this.clearPoints) {
      if (item.x1 > x || item.y1 > y || item.x2 < x || item.y2 < y) {
        count++
      } else {
        break
      }
    }
    if (len === count) {
      this.clearPoints.push({
        x1: x1,
        y1: y1,
        x2: x1 + this.r,
        y2: y1 + this.r
      })
    }
    if (len && this.r * this.r * len > this.scale * this.totalArea) {
      this.show = true
    }
    this.clearArcFun(x, y, this.r, this.ctx)
    this.ctx.draw(true)
  }

  clearArcFun (x, y, r, ctx) {
    let stepClear = 1
    clearArc(x, y, r)
    function clearArc (x, y, radius) {
      const calcWidth = radius - stepClear
      const calcHeight = Math.sqrt(radius * radius - calcWidth * calcWidth)

      const posX = x - calcWidth
      const posY = y - calcHeight

      const widthX = 2 * calcWidth
      const heightY = 2 * calcHeight

      if (stepClear <= radius) {
        ctx.clearRect(posX, posY, widthX, heightY)
        stepClear += 1
        clearArc(x, y, radius)
      }
    }
  }
}

export default Scratch

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章