vue实现拖动拼图验证码

现在许多网站的登录校验都加上了图片校验,这里用vue实现一个简单图形验证。如上图,我们需要有两个图层,不可拖动的底图和可拖动的拼图,使用canvas模拟两个图层。
# 绘制底图
使用ctx.drawImage绘制底图图片,使用ctx.getImageData获取随机拼图图片数据。随机拼图切图位置ry固定在图中心,rx在底图范围内随机
代码如下:
import imgSrc from './assets/img.png';
const width = ref(400);
const height = ref(250);
// 图形验证码
const rect = 50
let rx = 0//Math.max(rect * 2, Math.floor(Math.random() * (width.value - rect)))
const ry = height.value / 2 - rect / 2
let graphicImgData = null
const initImg = () => {
const img = new Image();
img.onload = () => {
drawImg(img);
};
img.src = imgSrc;
}
const drawImg = (img) => {
const ctx = canvasBack.value.getContext('2d');
// 清除Canvas
ctx.clearRect(0, 0, width.value, height.value);
// 计算缩放后的尺寸
const scaledWidth = img.width;
const scaledHeight = img.height;
// 计算绘制位置(居中显示)
const x = (width.value - scaledWidth) / 2;
const y = (height.value - scaledHeight) / 2;
// 绘制图片
ctx.drawImage(img, x, y, scaledWidth, scaledHeight);
// 获取随机的图形验证块
graphicImgData = ctx.getImageData(rx, ry, rect, rect);
// 绘制图形验证块阴影
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
ctx.shadowBlur = 15;
ctx.fillStyle = 'rgba(255, 255, 255, 0.566)';
ctx.fillRect(rx, ry, rect, rect);
// 绘制拖动拼图
// drawGraphic()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 绘制拖动拼图
使用ctx.putImageData将上面获取的图片数据绘制到第二个canvas上,代码如下:
const gx = ref(0)
let gy = ry
const drawGraphic = () => {
const ctxGraphic = canvasGraphic.value.getContext('2d');
ctxGraphic.clearRect(0, 0, width.value, height.value);
ctxGraphic.shadowColor = "rgba(255, 255, 255)";
ctxGraphic.shadowBlur = 10;
ctxGraphic.putImageData(graphicImgData, gx.value, gy);
ctxGraphic.shadowColor = "rgba(0, 0, 0, 0.5)";
ctxGraphic.shadowBlur = 15;
ctxGraphic.lineWidth = 0.2;
ctxGraphic.strokeStyle = 'white'
ctxGraphic.strokeRect(gx.value, gy, rect, rect);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 拖动拼图
- 鼠标按下时记录移动状态
- 鼠标移动时更新拼图位置并刷新
canvas拼图 - 鼠标抬起或移开时记录移动结束并检测校验是否验证成功
const moveStatus = ref(MoveStatus.value.NONE)
const onmousedown = (e) => {
if (moveStatus.value != MoveStatus.value.NONE) return;
console.log('onmousedown')
moveStatus.value = MoveStatus.value.MOVE
mStart = e.clientX;
}
const onmousemove = (e) => {
if (moveStatus.value === MoveStatus.value.MOVE) {
const moveX = e.clientX - mStart;
mStart = e.clientX;
gx.value = Math.min(Math.max(gx.value + moveX, 0), width.value - rect);
drawGraphic()
}
}
const onmouseup = () => {
moveStatus.value = MoveStatus.value.NONE;
checkMoveStatus()
}
const onmouseleave = () => {
moveStatus.value = MoveStatus.value.NONE;
checkMoveStatus()
}
const checkMoveStatus = () => {
if (Math.abs(gx.value - rx) <= 3) {
moveStatus.value = MoveStatus.value.SUCCESS;
} else {
moveStatus.value = MoveStatus.value.FAILURE;
// 重置位置
// gx.value = 0;
// drawGraphic();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 完整代码
上次更新: 2025/09/05, 8:09:00