移动端刮刮乐实现:基于HTML5 Canvas与globalCompositeOperation

作者:白露

时间:2026-10-21

浏览:587

本文介绍移动端刮刮乐的简单实现方式,核心利用HTML5 Canvas的globalCompositeOperation属性。通过设置destination-out实现涂抹透明效果,并结合getImageData获取像素数据计算擦除比例,当刮开面积超过3/4时触发CSS3动画自动消失,完整展示从布局到JS逻辑的代码实现。

文章目录

程序员往往具备一种惯性思维,面对带有动态效果或具有一定技术含量的交互元素时,总会下意识地去思考其背后的代码控制逻辑。例如电梯运行、路边霓虹灯闪烁、遥控器信号传输以及儿童玩具的运作机制等。

这种思维模式使得程序员在观察世界时,往往能透过表象看到更本质的技术实现原理。

移动端刮刮乐实现方案概述

相信大家都体验过线下刮刮乐,本文将介绍一种在移动端实现类似刮刮乐效果的技术方案,主要依赖于Canvas技术。

1、使用HTML 5 Canvas的globalCompositeOperation属性来实现刮刮乐效果

实现思路与Canvas合成原理

实现思路如下:

(1)首先需要一个容器进行定位,以确定刮刮乐区域在页面中的具体位置。

(2)在该定位容器内部,放置一个用于展示内容的容器,即存放奖品信息的区域。

(3)使用一个Canvas画布覆盖在上述容器之上,遮挡住奖品内容。

(4)当用户手指在屏幕上触摸并移动时,通过代码擦除画布的相应部分,从而露出下方的奖品区域。

(5)当擦除的面积达到一定比例(例如3/4)时,可以选择让画布自动消失,并伴随淡出动画效果(此步骤为可选功能)。

核心难点在于第四步,即如何实现擦除效果?

这里选用globalCompositeOperation,即Canvas中的合成操作。简单来说,Composite(组合)指的是后绘制的图形与先绘制的图形之间的组合显示效果。例如在国画中,红笔与绿笔相交会产生混色;而在油画中,绿色会覆盖红色。在程序绘图中,这种处理逻辑由Canvas API中的globalCompositeOperation函数实现。

globalCompositeOperation属性中包含一个名为“destination-out”的值,其含义是当新绘制的图形与已有图形重叠时,显示为透明。利用这一特性,我们可以在画布上进行“乱画”,画过的区域因重叠而变为透明,进而露出画布下方的内容,这正是我们期望的刮开效果。

HTML与CSS代码实现

HTML结构代码如下:


<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
 <title></title>
 <link rel="stylesheet" type="text/css" href="css/guaguale.css" rel="external nofollow" />
 </head>
 <body>
 <!-- 大的背景盒子-->
 <div id="main">
  <!-- 定位的盒子-->
  <div class="canvasBox">
  <!-- 放内容的盒子-->
  <span id="prize">
   恭喜发财,红包拿来
  </span>
  <!-- 蒙版画布-->
  <canvas id="canvas"></canvas>
  </div>
 </div>
 </body>
 <script type="text/javascript">
 var canvas = document.getElementById("canvas");
 var ctx = canvas.getContext('2d');
 /* 画布偏移量,下面用到的时候再介绍*/
 var arr = getOffset(canvas);
 var oLeft = arr[0];
 var oTop = arr[1];
 /* 初始化画布*/
 ctx.beginPath();
 ctx.fillStyle = '#ccc';
 ctx.fillRect(0,0,canvas.width,canvas.height);
 ctx.closePath();
 /* 增加触摸*/
 document.addEventListener("touchstart",function(){
  /* 初始化画笔*/
  ctx.beginPath();
  /* 画笔粗细*/
  ctx.lineWidth = 30;
  /* 设置组合效果*/
  ctx.globalCompositeOperation = 'destination-out';
  /* 移动画笔原点*/
  ctx.moveTo(event.touches[0].pageX-oLeft,event.touches[0].pageY-oTop);
 },false)
 document.addEventListener("touchmove",function(){
  /* 根据手指移动画线,使之变透明*/
  ctx.lineTo(event.touches[0].pageX-oLeft,event.touches[0].pageY-oTop);
  /* 填充*/
  ctx.stroke();
 })
 /* 之所以会用到下面的那个函数getOffset(obj)
  * 是因为event.touches[0].pageX、pageY获取的是相对于可视窗口的距离
  * 而lineTo画笔的定位是根据画布位置定位的
  * 所以就要先获取到画布(canvas)相对于可视窗口的距离,然后计算得出触摸点相对于画布的距离 
  * */
 /* 获取该元素到可视窗口的距离*/
 function getOffset(obj){
  var valLeft = 0,valTop = 0;
  function get(obj){
  valLeft += obj.offsetLeft;
  valTop += obj.offsetTop;
  /* 不到最外层就一直调用,直到offsetParent为body*/
  if (obj.offsetParent.tagName!='BODY') {
   get(obj.offsetParent);
  }
  return [valLeft,valTop];
  }
  return get(obj);
 }
 </script>
</html>

CSS样式代码如下:


*{
 margin: 0;
 padding: 0;
}
#main{
 width: 100%;
 padding: 20px 0;
 background-color: red;
}

.canvasBox{
 width: 78%;
 height: 160px;
 border-radius: 10px;
 background-color: #FFF;
 margin-left: 11%;
 line-height: 160px;
 text-align: center;
 position: relative;
}
#canvas{
 width: 96%;
 height: 96%;
 position: absolute;
 left: 2%;
 top: 2%;
 background-color: transparent;
}

像素级操作与擦除判断逻辑

第五步涉及Canvas像素点的获取,需要注意的是,像素级操作必须在服务器环境下运行才能生效。

getImageData(int x, int y, int width, int height):该方法用于获取Canvas上从坐标(x,y)开始,宽度为width、高度为height的图片区域数据。该方法返回一个CanvasPixelArray对象,该对象包含width、height、data等属性。其中,data属性是一个数组,每4个元素对应一个像素点的数据。

(注:图片的反相操作也可以通过修改rgba值来实现,原理类似)。

getImageData(int x, int y, int width, int height)返回的对象中,data数组存储了具体的像素点信息。

移动端刮刮乐实现方案概述

若打印data数组,可以看到data属性是一个数组,每4个元素对应一个像素点,以rgba的形式保存每个像素点的信息。

移动端刮刮乐实现方案概述

因此,我们可以根据像素点的opacity值(即data数组中每4个元素的第4个值)来判断该像素点是否透明,即判断其值是否等于0。

透明像素点的数量除以总像素点数量,即可得到擦除比例。

JavaScript核心代码与动画效果

JavaScript逻辑代码如下:


document.addEventListener("touchend",function(){
  /* 获取imageData对象*/
  var imageDate = ctx.getImageData(0,0,canvas.width,canvas.height);
  /* */
  var allPX = imageDate.width * imageDate.height;
  
  var iNum = 0;//记录刮开的像素点个数
  
  for(var i=0;i<allPX;i++){
  if(imageDate.data[i*4+3] == 0){
   iNum++;
  }
  }
  if(iNum >= allPX*3/4){
  // disappear里面写了缓慢清除的css3动画效果
  canvas.setAttribute('class','disappear'); 
  }
 },false)

“.disappear”类的CSS样式,用于实现CSS3的消失动画效果。


.disappear{
 -webkit-animation: disa 2s 1;
 animation: disa 2s 1;
 -webkit-animation-fill-mode: forwards;
 -moz-animation-fill-mode: forwards;
 -o-animation-fill-mode: forwards;
 animation-fill-mode: forwards;
}
@keyframes disa{
 0%{opacity:1;}
 100%{opacity: 0;}
}

相较于网络上其他一些实现方式,这种方法相对简单易懂,供各位开发者参考学习。如有其他更好的实现方案,欢迎留言交流。

以上就是本文的全部内容,希望本文的内容对大家的学习或工作能带来一定的帮助,同时也希望多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章