效果圖如下:
以下代碼僅為刮刮卡部分:
<template> <div class="scratch-card"> <div :style="computedBgStyle" class="scratch-card-bg"> <div class="canvas-wrap"> <div class="prize-wrap"> <h2 class="prize-item">一等獎</h2> <p class="prize-item">新秀麗行李箱新秀麗行李箱新秀麗行李箱新秀麗行李箱</p> </div> <canvas id="canvasMask" class="canvas"></canvas> </div> </div> </div> </template> <script> import { CTX, VERSION } from '@/constants/context' export default { props: { config: { type: Object, required: true } }, data() { return { canvas: null, context: null, width: 450, // canvas寬度 height: 250, // canvas高度 scaleRatio: 1 // 縮放比例 } }, computed: { computedBgStyle() { if(this.config.turnTableImg) { return { 'backgroundImage': `url(${this.config.turnTableImg})` } }else { return { 'backgroundImage': `url(${CTX}/static/img/scratch-card/prize-bg.png?v=${VERSION})` } } } }, mounted() { this.$nextTick(() => { const clientW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth this.scaleRatio = clientW / 750 this.canvas = document.getElementById('canvasMask') this.canvas.width = this.width * this.scaleRatio this.canvas.height = this.height * this.scaleRatio this.context = this.canvas.getContext('2d') // 畫灰色塗層圖片 const coatImg = new Image() coatImg.src = `${CTX}/static/img/scratch-card/coat-img.png?v=${VERSION}` coatImg.addEventListener('load', () => { this.context.drawImage(coatImg, 0, 0, this.canvas.width, this.canvas.height) // 啟用了globalCompositeOperation= = 'destination-out' 之后,在 canvs 上繪制的新的圖形,就會使得之前的 mask 變成透明的,從而顯示出背景圖片來。 this.context.globalCompositeOperation = 'destination-out' // 監聽touchmove this.canvas.addEventListener('touchmove', this.moveHandler) }) }) }, methods: {// 手指划過 畫圓 moveHandler(event) { let context = this.context event.preventDefault() context.beginPath() // 根據某個點在canvas上畫圓 // x 坐標和 y 坐標 兩個坐標是觸摸點的坐標而不是畫圓的圓心 // 圓心通過計算得出 var canvasRect = this.canvas.getBoundingClientRect() context.arc(event.touches[0].pageX - canvasRect.left, event.touches[0].pageY - canvasRect.top, 20 * this.scaleRatio, 0, Math.PI * 2) context.closePath() context.fillStyle = '#dddddd' context.fill() this.checkComplete() }, // 檢查完成度,判斷是否完成刮獎 點數大於80% checkComplete() { var imgData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) var pxData = imgData.data // 獲取字節數據 var len = pxData.length // 獲取字節長度 var count = 0 // 記錄透明點的個數 // 主要的思想是 一個像素由四個數據組成,每個數據分別是 rgba() 所以第四個數據 a 表示alpha透明度 for (var i = 0; i < len; i += 4) { var alpha = pxData[i + 3] // 獲取每個像素的透明度 if (alpha < 10) { // 透明度小於10 count++ } } var percent = count / (len / 4) // 計算百分比 // 如果百分比大於0.8 則表示成功 if (percent >= 0.8) { this.showResult() } }, // 顯示刮獎結果 showResult() { this.context.clearRect(0, 0, this.canvas.width, this.canvas.height) alert('刮獎成功') } } } </script> <style lang="scss" scoped> .scratch-card { width: px2rem(690px); height: px2rem(546px); margin: 0 auto; position: relative; &-bg { width: 100%; height: 100%; background-size: 100% 100%; padding-top: px2rem(204px); } } .canvas-wrap { width: px2rem(504px); height: px2rem(300px); background-image: img-url('../../assets/img/scratch-card/bg-scratch.png'); background-size: 100% 100%; margin: 0 auto; position: relative; color: #fff; text-align: center; .prize-wrap { height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; padding: 0 px2rem(30px); } .prize-item { @include font-dpr(30px); @include lh-dpr(42px); font-weight: 600; &:first-child { margin-bottom: px2rem(16px); } } .canvas { background-size: 100% 100%; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } } </style>