我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛
前言
上文说自己也写一段代码试试,突然想试着实现一个刮刮乐,正巧碰到活动了,想着中秋节店家抽奖也一定用得上,那就顺便参加活动,一起做出来
成品展示
重点分析
- 绝对定位覆盖内容
<canvas></canvas>可以实现绘画以及擦除- 扩展性:覆盖图片、覆盖文字
- CSS 画月亮
代码解读
我还是觉得写成模板化的形式挺好的,但是不太熟练,所以还是抄了一个骨架
class Something {
constructor() {
}
render() {
}
...
}
大概就是这样!
先想,一个刮刮乐可以拥有什么属性:
- id
- 内容
- 长宽
- ……
所以在 constructor() 中我也设置了这些属性。
再想,这个刮刮乐应该使用啥 HTML 结构来表示:
-
div.scratch-content表示内容注意点:文字和图片使用了两种标签,所以实际标签应该是这样的
div.scratch-content > imgdiv.scratch-content > div
-
<canvas width=${this.width} height=${this.height}></canvas>表示刮层注意点:
所以 render() 中我要返回如下结构的 HTML 代码
render() {
if (this.content.img !== undefined)
return `
<div class="scratch-content"><img alt="" src="${this.content.img}"></div>
<canvas title="" id="cover-layer" width="${this.width}" height="${this.height}"></canvas>
`;
return `
<div class="scratch-content"><div>${this.content.text}</div></div>
<canvas title="" id="cover-layer" width="${this.width}" height="${this.height}"></canvas>
`;
}
此时, constructor() 可以生成结构了
现在的构造函数应该长这样
constructor(id, content = { img: "", text: "" }, width = 300, height = 150) {
this.container = document.getElementById(id);
this.content = content;
this.width = width;
this.height = height;
this.mousedown = false;
this.container.innerHTML = this.render();
this.canvas = document.getElementById("cover-layer");
this.ctx = this.canvas.getContext("2d");
}
紧接着,我们可以绘制刮层了
刮层也很容易实现,因为我们在 constructor() 已经声明 canvas 上下文了,可以直接使用,代码如下:
cover() {
this.ctx.fillStyle = "#555";
this.ctx.fillRect(0, 0, this.width, this.height);
}
那么,如何实现擦除呢?
erase(x, y) {
this.ctx.globalCompositeOperation = "destination-out";
this.ctx.beginPath();
this.ctx.arc(x, y, 15, 0, 2 * Math.PI);
this.ctx.fill();
this.ctx.closePath();
}
这里使用了globalCompositeOperation,说实话,我实在不太会用汉语描述一遍这到底是干嘛的,所以看链接吧
这里还有一个注意点:this.ctx.beginPath() 如果不加这句,擦除会有索套的效果,可以删除试一下!
arc的参数分别是:x,y,半径,起始角度,结束角度,fill()当然就是填充啦!
当然,我们需要一个初始化函数!
初始化做啥捏?事实上我们生成 HTML 后就要绘制图层啦,还有我们需要绑定鼠标经过移动事件等等
大概大概结构就是这样的捏:
init() {
this.cover();
// touch 移动端 mouse PC端
this.canvas.ontouchstart = this.container.onmousedown = () => {
this.mousedown = true;
};
this.canvas.ontouchcancel = this.container.onmouseup = () => {
this.mousedown = false;
};
this.canvas.addEventListener("mousemove", (e) => {
if (this.mousedown) {
this.erase(e.offsetX, e.offsetY);
}
});
this.canvas.addEventListener("touchmove", (e) => {
if (this.mousedown) {
this.erase(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
}
});
}
好啦!我们写完测试一下!
按照我们写的构造函数 new 一个新的刮刮乐!
const scratchCard__img = new ScratchCard(
"scratchCard__img",
{
img:
"https://sf1-ttcdn-tos.pstatp.com/obj/larkcloud-file-storage/baas/qcnp4x/f0d1c4f16359d534_1631099749185.jpg"
},
450,
240
);
呐呐呐!如果是文字版的就可以这样
const scratchCard__text = new ScratchCard(
"scratchCard__text",
{
text:
"233333"
},
450,
240
);
最最后,我们画一个月亮!
核心代码是这样的!使用伪元素、给宽高、给bgc、给边框半径,然后!一个月亮就出来啦!
.header::before {
content: " ";
background-color: #ccdd00;
width: 90px;
height: 90px;
border-radius: 50%;
}
结束语
恩~大家中秋节快乐啦! 实在没啥好活,给各位献丑了!欢迎讨论还有点赞!
相关链接
- : The Graphics Canvas element - HTML: HyperText Markup Language | MDN (mozilla.org)
- : The Graphics Canvas element - HTML: HyperText Markup Language | MDN (mozilla.org)
- CanvasRenderingContext2D.globalCompositeOperation - Web APIs | MDN (mozilla.org)
- CanvasRenderingContext2D - Web APIs | MDN (mozilla.org)
- HTMLCanvasElement - Web APIs | MDN (mozilla.org)
\