Vue用canvas实现移动端刮刮奖

465 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第四天,点击查看活动详情


前言

上文提到了用组件的方式来实现刮刮奖,本文笔者将用canvas覆盖源图像的方式来自己实现。

实现

1.定义模板

<template>
  <div>
    <div
      id="1"
      class="scratchCard"
      :style="'width:' + width + ';height:' + height"
    >
      <--源图像层-->
      <div class="result"></div>
      <--覆盖层-->
      <canvas id="canvas"></canvas>
    </div>
  </div>
</template>

2.开始初始化canvas画布并定义样式

mounted() {
      this.init();
  },
  methods: {
    init() {
      if (!this.isSupportCanvas()) {
        alert("当前浏览器不支持canvas");
        return;
      }
      //创建画布并添加样式
      const canvasWrap = document.getElementById("1");
      this.canvas = canvasWrap.querySelector("#canvas");
      this.ctx = this.canvas.getContext("2d");
      this.canvas.width = canvasWrap.clientWidth;
      this.canvas.height = canvasWrap.clientHeight;
      this.ctx.fillstyle = "#a0a0a0";
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
      //开始绑定事件
      this.bindevent();
    },
}

3.添加判断并开始事件处理

    bindevent() {
      //判断是移动端还是pc端操作
      if ("ontouchstart" in window) this.supportTouch = true;
      this.events = this.supportTouch
        ? ["touchstart", "touchmove", "touchend"]
        : ["mousedown", "mousemove", "mouseup"];
      this.canvas.addEventListener(
        this.events[0],
        this.startEventHandler,
        false
      );
    },
    startEventHandler(e) {
      //防止触摸时滑动滚动条
      e.preventDefault();
      //创建开始触摸事件回调(可自行添加逻辑处理)
      if (this.firstTouch) {
        this.startCallback();
        this.firstTouch = false;
      }
      //显示奖品层在底层
      this.showLucky = true;
      //监听移动事件
      this.canvas.addEventListener(
        this.events[1],
        this.moveEventHandler,
        false
      );
      document.addEventListener(this.events[2], this.endEventHandler, false);
    },

4.对于移动事件进行处理

moveEventHandler(e) {
      e.preventDefault();
      //判断为触摸还是鼠标
      e = this.supportTouch ? e.touches[0] : e;
      //getBoundingClientRect用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
      const canvasPos = this.canvas.getBoundingClientRect(),
        scrollT = document.documentElement.scrollTop || document.body.scrollTop,
        scrollL =
          document.documentElement.scrollLeft || document.body.scrollLeft,
        mouseX = e.pageX - canvasPos.left - scrollL,
        mouseY = e.pageY - canvasPos.top - scrollT;
      this.ctx.beginPath();
      this.ctx.fillStyle = "#FFFFFF";
      //在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
      this.ctx.globalCompositeOperation = "destination-out";
      //创建弧/曲线(用于创建圆形或部分圆)
      this.ctx.arc(mouseX, mouseY, this.moveRadius, 0, 2 * Math.PI);
      this.ctx.fill();
    },
   endEventHandler(e) {
      e.preventDefault();
      //移除事件句柄
      this.canvas.removeEventListener(this.events[1], this.moveHandler, false);
      document.removeEventListener(this.events[2], this.endMoveHandler, false);
      this.endMoveHandler = null;
      this.caleArea();
    },
    caleArea() {
      let pixels = this.ctx.getImageData(
          0,
          0,
          this.canvas.width,
          this.canvas.height
        ),
        transPixels = [];
      pixels.data.map((item, i) => {
        const pixel = pixels.data[i + 3];
        if (pixel === 0) {
          transPixels.push(pixel);
        }
      });
      //判断刮得比例,大于这个比例之和就彻底清除
      if (transPixels.length / pixels.data.length > this.ratio) {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.canvas.removeEventListener(this.events[0], this.startEventHandler);
        this.canvas.removeEventListener(
          this.events[1],
          this.moveEventHandler,
          false
        );
        document.removeEventListener(
          this.events[2],
          this.endEventHandler,
          false
        );
        //结束的回调函数(可添加逻辑处理)
        this.clearCallback();
      }
    },

5.实现效果

背景文字

31h2h-wsez0.gif

图片

3je14-dp4fq.gif

总结

本文通过canvas画布实现了简单的刮刮奖,借鉴了网上的一些文章的经验完成,希望大家能够有所收获!