vue实现刮奖
Vue 实现刮奖功能
刮奖功能通常通过 Canvas 或遮罩层实现,以下是两种常见方法的实现步骤:
使用 Canvas 实现
创建一个 Vue 组件,利用 HTML5 Canvas 的绘图功能模拟刮奖效果。
<template>
<div class="scratch-card">
<canvas
ref="canvas"
@mousedown="startScratch"
@mousemove="scratch"
@mouseup="endScratch"
@touchstart="startScratch"
@touchmove="scratch"
@touchend="endScratch"
></canvas>
<div class="prize">{{ prize }}</div>
</div>
</template>
<script>
export default {
data() {
return {
isDrawing: false,
prize: '一等奖',
canvas: null,
ctx: null
}
},
mounted() {
this.initCanvas()
},
methods: {
initCanvas() {
this.canvas = this.$refs.canvas
this.ctx = this.canvas.getContext('2d')
// 设置canvas尺寸
this.canvas.width = 300
this.canvas.height = 150
// 绘制刮奖层
this.ctx.fillStyle = '#999'
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.font = '20px Arial'
this.ctx.fillStyle = '#000'
this.ctx.fillText('刮开查看', 100, 75)
},
startScratch(e) {
this.isDrawing = true
this.scratch(e)
},
scratch(e) {
if (!this.isDrawing) return
const rect = this.canvas.getBoundingClientRect()
const x = (e.clientX || e.touches[0].clientX) - rect.left
const y = (e.clientY || e.touches[0].clientY) - rect.top
// 使用圆形擦除
this.ctx.globalCompositeOperation = 'destination-out'
this.ctx.beginPath()
this.ctx.arc(x, y, 15, 0, Math.PI * 2)
this.ctx.fill()
},
endScratch() {
this.isDrawing = false
}
}
}
</script>
<style>
.scratch-card {
position: relative;
width: 300px;
height: 150px;
}
.prize {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: -1;
}
canvas {
border: 1px solid #ccc;
}
</style>
使用 CSS 遮罩实现
对于简单需求,可以使用 CSS 的 mask 属性实现刮奖效果。
<template>
<div
class="scratch-mask"
@mousedown="startScratch"
@mousemove="scratch"
@mouseup="endScratch"
@touchstart="startScratch"
@touchmove="scratch"
@touchend="endScratch"
:style="maskStyle"
>
<div class="prize">{{ prize }}</div>
</div>
</template>
<script>
export default {
data() {
return {
isDrawing: false,
prize: '二等奖',
points: []
}
},
computed: {
maskStyle() {
if (this.points.length === 0) return {}
let radialGradients = this.points.map(point =>
`radial-gradient(circle 15px at ${point.x}px ${point.y}px, transparent 0, transparent 15px, black 15px)`
).join(', ')
return {
'-webkit-mask-image': radialGradients,
'mask-image': radialGradients
}
}
},
methods: {
startScratch(e) {
this.isDrawing = true
this.addPoint(e)
},
scratch(e) {
if (!this.isDrawing) return
this.addPoint(e)
},
endScratch() {
this.isDrawing = false
},
addPoint(e) {
const rect = e.target.getBoundingClientRect()
const x = (e.clientX || e.touches[0].clientX) - rect.left
const y = (e.clientY || e.touches[0].clientY) - rect.top
this.points.push({ x, y })
}
}
}
</script>
<style>
.scratch-mask {
width: 300px;
height: 150px;
background-color: #999;
position: relative;
-webkit-mask-composite: source-out;
mask-composite: subtract;
}
.prize {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
</style>
优化建议
- 对于移动端,确保添加 touch 事件支持
- 可以添加刮开比例检测,当刮开面积超过一定比例时自动显示全部内容
- 考虑添加动画效果提升用户体验
- 对于复杂需求,可以考虑使用第三方库如
scratchcard-js
两种方法各有优劣,Canvas 实现更灵活但代码量稍多,CSS 实现更简洁但兼容性稍差。根据项目需求选择合适方案。







