先来一张图看看,这是现实中的,那么我们如何在程序上实现这样的效果呢,主流方案是采用canvas来实现
首先要实现这种效果,核心点是了解canvas的globalCompositeOperation属性,这个属性的作用是控制canvas上不同图层之间的显示效果,传送门
我们这里只需要使用到"destination-out"属性,这个属性描述的效果是,当新图层绘制到原始图层上时候,原始图层保持在新图层不重叠的部分
有了这个效果之后,我们只需要将要显示的东西放置在canvas后面就可以了,至于刮卡的效果,就是在mosemove事件里面,动态绘制透明的图层到canvas上就好了
<script setup lang="ts"> import { onMounted, shallowRef } from "vue"; const w = 300, h = 150; const ctx = shallowRef<CanvasRenderingContext2D | null>(null); const mousedown = shallowRef(false); function init() { const canvas = document.getElementById("scratch") as HTMLCanvasElement; canvas.addEventListener("touchstart", eventDown); //鼠标移动开始 canvas.addEventListener("touchend", eventUp); //鼠标移动结束 canvas.addEventListener("touchmove", eventMove); //鼠标移动 canvas.addEventListener("mousedown", eventDown); //鼠标点击 canvas.addEventListener("mouseup", eventUp); //鼠标松开 canvas.addEventListener("mousemove", eventMove); //鼠标移动中 ctx.value = canvas.getContext("2d"); if (ctx.value) { ctx.value.fillStyle = "gray"; //灰色 ctx.value.fillRect(0, 0, w, h); //顶部绘图填充矩阵灰色 ctx.value.globalCompositeOperation = "copy"; } } function eventDown(e) { //监听鼠标按住 e.preventDefault(); mousedown.value = true; } function eventUp(e) { //监听鼠标松开 e.preventDefault(); mousedown.value = false; } function eventMove(e) { //监听鼠标按住并移动,执行绘图函数 e.preventDefault(); if (mousedown.value) { var x = (e.clientX + document.body.scrollLeft || e.pageX) - 0 || 0, y = (e.clientY + document.body.scrollTop || e.pageY) - 0 || 0; ctx?.value?.beginPath(); //绘图开始路径 ctx?.value?.rect(x, y, 20, 20); //创建一个正方形刮刮痕迹形状 ctx?.value?.fill(); } } onMounted(() => { init(); }); </script> <template> <div> <canvas id="scratch" width="300px" height="150px"></canvas> <div id="background" class="w-300px h-150px bg-blue absolute top-0 left-0 z--1" ></div> </div> </template> <style> #background { background-size: contain; background-image: url("https://wallpaperm.cmcm.com/b26f4834677e2f0c2cedbd24788b4362.jpg"); } </style>
标签:canvas,鼠标,效果,前端,ctx,value,刮刮卡,addEventListener,图层 From: https://www.cnblogs.com/aursordev/p/18354436