• 不使用canvas怎么实现一个刮刮卡效果?


    说在前面

    🎈刮刮卡大家应该都玩过吧,还记得小时候的小卖部总会有各种各样的刮卡抽奖活动,刮卡时那心跳的感觉让我们更加的欲罢不能,随着时代的发展,现在很多回忆也都有了网页版,通过canvas我们可以很方便的实现一个刮刮卡的功能效果,那么不使用canvas的话呢?我们也可以很快速的实现这个功能!

    效果预览

    • canvas模式
      在这里插入图片描述

    • dom模式
      在这里插入图片描述

    体验地址

    http://jyeontu.xyz/jvuewheel/#/JScratchCard

    组件实现

    设计图

    在这里插入图片描述

    我们可以使用若干个小块来拼接成完整的一大块涂层,后面只需要判断鼠标事件,将鼠标划过的小块设置样式透明即可,有了大致的思路之后我们便可以开始动手来开始敲代码了。

    参数说明

    • width

    刮刮卡的宽度,默认为300px

    • height

    刮刮卡的高度,默认为200px

    • mode

    刮刮卡的模式,有canvas和dom两种模式,默认为canvas模式

    • color

    刮刮卡涂层颜色,默认为gray

    • block

    刮刮卡涂层小块配置,mode为dom时需要设置小块的宽度width和高度height

    功能实现

    一、dom模式

    html

    刮刮卡的内容通过插槽的方式传入展示。

    <div :id="uid + 'j-scratch-card'" class="j-scratch-card">
        <div :id="uid + 'j-scratch-card-bg'" class="j-scratch-card-bg">
            <slot name="j-scratch-card-bg-slot">slot>
        div>
        <div
            :id="uid + 'j-scratch-card-mask'"
            class="j-scratch-card-mask"
        >div>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    初始化刮刮卡样式

    通过传入参数初始化刮刮卡样式。

    const scratchCardId = this.uid + "j-scratch-card";
    const scratchCardDom = document.getElementById(scratchCardId);
    scratchCardDom.style.width = this.width;
    scratchCardDom.style.height = this.height;
    
    • 1
    • 2
    • 3
    • 4
    生成刮刮卡涂层小块

    计算应该生成的小块行数和列数。

    const block = this.block;
    const col = Math.ceil(
        parseInt(this.height) / parseInt(block.height)
    );
    const row = Math.ceil(parseInt(this.width) / parseInt(block.width));
    for (let i = 0; i < col; i++) {
        const colDom = document.createElement("div");
        colDom.style = "display:flex;";
        colDom.classList.add("j-scratch-card-mask-col");
        for (let j = 0; j < row; j++) {
            const rowDom = document.createElement("div");
            rowDom.classList.add("j-scratch-card-mask-row");
            rowDom.id = `j-scratch-card-mask-row-${col}-${row}`;
            rowDom.style = `width:${block.width};height:${block.height};background-color: ${this.color};`;
            rowDom.addEventListener("mouseover", e => {
                if (!this.isMouseDown) return;
                e.target.style.opacity = "0";
            });
            colDom.appendChild(rowDom);
        }
        scratchCardMaskDom.appendChild(colDom);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    监听鼠标事件

    监听涂层的鼠标事件。

    const scratchCardMaskId = this.uid + "j-scratch-card-mask";
    const scratchCardMaskDom = document.getElementById(
        scratchCardMaskId
    );
    scratchCardMaskDom.addEventListener("mousedown", () => {
        this.isMouseDown = true;
    });
    window.addEventListener("mouseup", () => {
        this.isMouseDown = false;
    });
    window.addEventListener("dragend", () => {
        this.isMouseDown = false;
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    二、canvas模式

    相比于dom原生实现,canvas实现的效果和性能会更好,所以主流还是使用canvas来实现刮刮卡的效果,所以这里我也实现了canvas模式的刮刮卡。

    html
    <div style="position: relative;" v-if="mode == 'canvas'">
        <canvas
            :id="uid + '-canvas'"
            :width="parseInt(width)"
            :height="parseInt(height)"
        >
        canvas>
        <div class="canvas-bg">
            <slot name="j-scratch-card-bg-slot">slot>
        div>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    初始化刮刮卡样式

    通过传入参数初始化刮刮卡样式。

    const canvas = document.getElementById(this.uid + "-canvas");
    const ctx = canvas.getContext("2d");
    // 填充的颜色
    ctx.fillStyle = this.color;
    // 填充矩形 fillRect(起始X,起始Y,终点X,终点Y)
    ctx.fillRect(0, 0, parseInt(this.width), parseInt(this.height));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    监听鼠标事件

    监听涂层的鼠标事件。

    canvas.onmousedown = () => {
        this.isMouseDown = true;
    };
    canvas.onmousemove = e => {
        if (!this.isMouseDown) return;
        // 计算鼠标在canvas里的位置
        const x = e.layerX - canvas.offsetLeft;
        const y = e.layerY - canvas.offsetTop;
        // 设置globalCompositeOperation
        ctx.globalCompositeOperation = "destination-out";
        // 画圆
        ctx.arc(x, y, 10, 0, 2 * Math.PI);
        // 填充圆形
        ctx.fill();
    };
    canvas.onmouseup = () => {
        this.isMouseDown = false;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    组件库引用

    这里我将这个组件打包进了自己的一个组件库,并将其发布到了npm上,有需要的同学也可以直接引入该组件进行使用。
    引入教程可以看这里:http://jyeontu.xyz/jvuewheel/#/installView
    引入后即可直接使用。

    源码地址

    组件库已开源,想要查看完整源码的可以到 gitee 查看,自己也整理了相关的文档对其进行了简单介绍,具体如下:

    组件文档

    jvuewheel: http://jyeontu.xyz/jvuewheel/#/JScratchCard

    Gitee源码

    Gitee源码:gitee.com/zheng_yongt…

    觉得有帮助的同学可以帮忙给我点个star,感激不尽~~~
    有什么想法或者改良可以给我提个pr,十分欢迎~~~
    有什么问题都可以在评论告诉我~~~

    往期精彩

    vue封装一个3D轮播图组件

    vue实现一个鼠标滑动预览视频封面组件(精灵图版本)

    node封装一个图片拼接插件

    基于inquirer封装一个控制台文件选择器

    node封装一个控制台进度条插件

    密码太多不知道怎么记录?不如自己写个密码箱小程序

    微信小程序实现一个手势图案锁组件

    vue封装一个弹幕组件

    为了学(mo)习(yu),我竟开发了这样一个插件

    程序员的浪漫之——情侣日常小程序

    vue简单实现词云图组件

    说在后面

    🎉这里是JYeontu,喜欢算法,GDCPC打过卡;热爱羽毛球,大运会打过酱油。毕业一年,两年前端开发经验,目前担任H5前端开发,算法业余爱好者,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。

  • 相关阅读:
    FreeRTOS简单内核实现7 阻塞链表
    企业文化对于营造积极向上的工作氛围有多大影响?
    python抓取网页视频
    【Java】你会使用 Lambda 表达式吗?
    LAMMPS模拟:液滴润湿表面的铺展长度统计及Matlab平均计算
    tar.gz文件修复
    马斯克440亿美元收购Twitter一年后:全力“下云”,成本速降60%,功能代码从70万行减少至7万!...
    集合深度学习02—List
    hadoop常用命令
    uniapp 分享到朋友圈
  • 原文地址:https://blog.csdn.net/Twinkle_sone/article/details/126473289