JavaScript实现滑块补图验证码效果
作者:寅时码
这篇文章主要给大家介绍了JavaScript如何实现滑块补图验证码效果,文章通过代码示例介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴可以参考阅读下
<div class="container"> <div class="pic"> <div class="gap"></div> <div class="verify-pic"></div> </div> <div class="slide"> <div class="btn"></div> </div> </div>
没错,全部手工绘制,不用任何图片、svg、字体图标之流
pic
为背景图片,里面放着gap
空白块,verify-pic
被拖动的验证图
slide
是滑块,btn
是小按钮
样式
首先初始化样式和变量
:root { --btn-w: 40px; --btn-h: 24px; /* 按钮伪元素 */ --btn-dot-w: 4px; /* 滑块 */ --bar-h: 10px; /* 背景图 */ --pic-w: 640px; --pic-h: 390px; --pic-src: url(https://i0.hdslb.com/bfs/vc/c13315f4c4195b342fd0d2795fd6c8b090a717bf.jpg); --radius: 8px; } * { margin: 0; padding: 0; }
这几个样式很大众 没什么可讲的
.container { display: flex; position: relative; height: var(--pic-h); width: var(--pic-w); flex-flow: column wrap; justify-content: space-between; padding: 10px; } .pic { position: relative; background: var(--pic-src) no-repeat; width: 640px; height: 340px; } .slide { position: relative; width: 100%; height: var(--bar-h); background-color: #999; border-radius: 4px; }
.btn { position: absolute; left: 0; /* (按钮高度 - 拖动条高度) * -1 / 2 */ top: calc((var(--btn-h) - var(--bar-h)) * -1 / 2); width: var(--btn-w); height: var(--btn-h); background-color: #b5a37e; border-radius: 10px; cursor: pointer; }
这个滑块按钮,要想在垂直方向居中,就需要拿按钮高度 - 滑动条高度 / 2
但是为什么要 乘以 -1
呢??
因为DOM
坐标系是第三象限,负值为向上
接下来是里面的俩小薯条了
.btn::after, .btn::before { content: ""; position: absolute; top: 50%; transform: translateY(-50%); left: calc(var(--btn-w) / 3 - var(--btn-dot-w) / 2); height: var(--bar-h); width: var(--btn-dot-w); background-color: #eee; }
这里我把整个滑块分成三份,所以位置就是滑块的三分之一,后面的小薯条除以2是为了居中
.btn::before { /* 伪元素在按钮的 2/ 3处 并减去自己的一半用来居中 */ left: calc(var(--btn-w) / 3 * 2 - var(--btn-dot-w) / 2); }
第二个小薯条就是三分之二的位置即可
至此 样式完成
操作逻辑 & 效果实现
const container = document.querySelector('.container'), pic = container.querySelector('.pic'), // 大图 vPic = pic.querySelector('.verify-pic'), // 拖动图片 gap = pic.querySelector('.gap'), // 背景图空白块 btn = document.querySelector('.btn'); // 滑动条按钮 const pic_w = getStyle(pic, 'width'), pic_h = getStyle(pic, 'height'), cont_w = getStyle(container, 'width'), cont_h = getStyle(container, 'height'), vPic_w = getStyle(vPic, 'width'), vPic_h = getStyle(vPic, 'height'), btn_w = getStyle(btn, 'width'); const offset = 14; // 可偏移距离 function getRadom(min, max) { return Math.floor(min + Math.random() * (max - min)); } function getStyle(el, key) { return parseInt(getComputedStyle(el)[key]); }
先获取DOM
以及设置配置
这里一定不能用offset
系列获取矩形属性,因为隐藏的元素无法获取
初始化位置
function setPos() { const w = pic_w / 2, h = pic_h / 2 - vPic_h; // 移动空缺元素到右上部分 const left = getRadom(w, pic_w - vPic_w), top = getRadom(0, h); gap.style.transform = `translate(${left}px, ${top}px)`; vPic.style.backgroundPosition = `${-left}px ${-top}px`; return [left, top]; }
把滑块和图片 移动到右上方随机位置
返回值作为最终对比值
由于left
是指元素左边的距离,所以要减去元素宽度
let x = 0, // 滑倒最后的值 moving = false; btn.addEventListener('mousedown', function (e) { moving = true; setShow(top, 'block'); }); btn.addEventListener('mouseup', function () { setShow(top, 'none'); }); function setShow(top, flag) { vPic.style.display = flag; vPic.style.transform = `translateY(${top}px)`; btn.style.transform = 'none'; vPic.style.transform = 'none'; x = 0; }
这里的setShow
可复用多次
现在有什么问题吗??
问题大着呢,你把mouseup
绑在了小按钮上,当你抬起位置不是按钮,就不能触发了
正确做法是绑定在window
上
接下来是重点,滑动事件
window.addEventListener('mousemove', function (e) { if (!moving) { return; } // 图片位置 = 鼠标位置 - 滑动条位置 - 按钮 / 2 ----减去按钮是居中 x = e.clientX - container.getBoundingClientRect().left - btn_w / 2; btn.style.transform = `translateX(${x}px)`; vPic.style.transform = `translate(${x}px, ${top}px)`; });
window.addEventListener('mousemove', function (e) { if (!moving) { return; } // 图片位置 = 鼠标位置 - 滑动条位置 - 按钮 / 2 ----减去按钮是居中 x = e.clientX - container.getBoundingClientRect().left - btn_w / 2; btn.style.transform = `translateX(${x}px)`; vPic.style.transform = `translate(${x}px, ${top}px)`; });
这样基本就实现了,但是没有判断边界呢,现在可以随意滑动
function judge(x) { const { left } = container.getBoundingClientRect(); return ( x - left < 0 || x + left > cont_w + left ); } window.addEventListener('mousemove', function (e) { if (!moving || judge(e.clientX)) { return; } // 图片位置 = 鼠标位置 - 滑动条位置 - 按钮 / 2 ----减去按钮是居中 x = e.clientX - container.getBoundingClientRect().left - btn_w / 2; btn.style.transform = `translateX(${x}px)`; vPic.style.transform = `translate(${x}px, ${top}px)`; });
当x
轴小于0
或者鼠标大于图片宽度时退出
这时候给x
赋值,鼠标抬起时判断
window.addEventListener('mouseup', function () { const flag = x > left - offset && x < left + offset; moving = false; if (flag) { cb && cb(); } else { setShow(top, 'none'); } });
如果成功 执行外面的回调函数 反之重置位置
现在基本完全实现
就在我喜出望外之际,我发现滑动一些刁钻的角度,会让鼠标属性改变,变成这样
cursor: not-allowed;
因为这个原因,会扰乱事件
但是我整篇代码也没设置过
所以我冥思苦想
那一定是事件默认行为搞的鬼
所以我给每个元素阻止了默认行为,最终排查发现,是mousedown
导致的
btn.addEventListener('mousedown', function (e) { // 不阻止默认行为 会导致鼠标属性变成 `now-allowed` e.preventDefault(); moving = true; setShow(top, 'block'); });
以上就是JavaScript实现滑块补图验证码效果的详细内容,更多关于JavaScript滑块补图验证码的资料请关注脚本之家其它相关文章!