当前位置:首页 > VUE

移动端vue实现刮刮卡

2026-01-22 17:48:09VUE

移动端vue实现刮刮卡

移动端 Vue 实现刮刮卡效果

在移动端实现刮刮卡效果需要结合 Canvas 绘图和触摸事件监听。以下是一个完整的实现方案:

移动端vue实现刮刮卡

创建 Vue 组件结构

<template>
  <div class="scratch-container">
    <canvas 
      ref="canvas" 
      @touchstart="handleTouchStart" 
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    ></canvas>
    <div class="prize-content">{{ prizeText }}</div>
  </div>
</template>

初始化 Canvas 和绘图

export default {
  data() {
    return {
      isDrawing: false,
      ctx: null,
      canvas: null,
      prizeText: "恭喜中奖!",
      canvasSize: { width: 300, height: 150 }
    }
  },
  mounted() {
    this.initCanvas();
  },
  methods: {
    initCanvas() {
      this.canvas = this.$refs.canvas;
      this.ctx = this.canvas.getContext('2d');

      this.canvas.width = this.canvasSize.width;
      this.canvas.height = this.canvasSize.height;

      // 绘制覆盖层
      this.ctx.fillStyle = '#999';
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
      this.ctx.globalCompositeOperation = 'destination-out';
    }
  }
}

处理触摸事件

methods: {
  handleTouchStart(e) {
    e.preventDefault();
    this.isDrawing = true;
    const pos = this.getTouchPos(e);
    this.ctx.beginPath();
    this.ctx.moveTo(pos.x, pos.y);
  },

  handleTouchMove(e) {
    if (!this.isDrawing) return;
    e.preventDefault();
    const pos = this.getTouchPos(e);
    this.ctx.lineTo(pos.x, pos.y);
    this.ctx.lineWidth = 20;
    this.ctx.lineCap = 'round';
    this.ctx.lineJoin = 'round';
    this.ctx.stroke();
  },

  handleTouchEnd() {
    this.isDrawing = false;
    this.checkScratchCompletion();
  },

  getTouchPos(e) {
    const rect = this.canvas.getBoundingClientRect();
    return {
      x: e.touches[0].clientX - rect.left,
      y: e.touches[0].clientY - rect.top
    };
  }
}

检查刮卡完成度

methods: {
  checkScratchCompletion() {
    const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
    const pixels = imageData.data;
    let transparentPixels = 0;

    for (let i = 0; i < pixels.length; i += 4) {
      if (pixels[i + 3] === 0) {
        transparentPixels++;
      }
    }

    const transparentRatio = transparentPixels / (pixels.length / 4);
    if (transparentRatio > 0.6) {
      this.$emit('completed');
    }
  }
}

添加样式

.scratch-container {
  position: relative;
  width: 300px;
  height: 150px;
  margin: 0 auto;
}

canvas {
  position: absolute;
  top: 0;
  left: 0;
  touch-action: none;
}

.prize-content {
  position: absolute;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff8e1;
  font-size: 18px;
  color: #ff6d00;
}

优化移动端体验

为提升移动端体验,可以添加以下优化:

// 在 mounted 中添加
document.addEventListener('touchmove', this.preventScroll, { passive: false });

// 在 methods 中添加
preventScroll(e) {
  if (this.isDrawing) {
    e.preventDefault();
  }
},

// 在 beforeDestroy 中移除
beforeDestroy() {
  document.removeEventListener('touchmove', this.preventScroll);
}

组件使用示例

<template>
  <div>
    <h3>刮刮卡</h3>
    <scratch-card @completed="handleComplete" />
  </div>
</template>

<script>
import ScratchCard from './ScratchCard.vue';

export default {
  components: { ScratchCard },
  methods: {
    handleComplete() {
      alert('刮卡完成!');
    }
  }
}
</script>

这个实现方案包含了完整的移动端触摸事件处理、Canvas绘图逻辑和刮卡完成度检测,可以直接在Vue项目中使用。

标签: 刮刮卡vue
分享给朋友:

相关文章

vue实现socket

vue实现socket

Vue 中实现 WebSocket 通信 在 Vue 项目中实现 WebSocket 通信可以通过原生 WebSocket API 或第三方库(如 socket.io-client)完成。以下是两种常…

vue 实现过滤

vue 实现过滤

Vue 实现过滤的方法 在 Vue 中实现过滤功能可以通过多种方式完成,包括使用计算属性、自定义过滤器、第三方库等。以下是几种常见的实现方法: 使用计算属性进行过滤 计算属性是 Vue 中最常用的过…

vue实现链接

vue实现链接

Vue 实现链接的方法 在 Vue 中实现链接可以通过多种方式,包括使用 <router-link>、<a> 标签或编程式导航。以下是几种常见的方法: 使用 <rout…

vue实现导入

vue实现导入

Vue 实现文件导入功能 使用 <input type="file"> 元素 在 Vue 模板中添加一个文件输入元素,绑定 change 事件处理函数。 <template>…

vue实现等级选择

vue实现等级选择

实现等级选择的方法 在Vue中实现等级选择功能,可以通过多种方式完成,以下是几种常见的实现方法: 使用v-for渲染星级选择 通过v-for指令循环渲染星级图标,结合点击事件实现等级选择: <…

vue弹幕实现暂停

vue弹幕实现暂停

实现 Vue 弹幕暂停功能 监听播放状态 通过 v-model 或自定义事件绑定弹幕组件的播放状态,存储一个布尔值(如 isPlaying)控制播放与暂停。在弹幕滚动逻辑中根据该状态判断是否更新位置。…