JavaScript實現(xiàn)滑塊補圖驗證碼效果

<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、字體圖標(biāo)之流
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坐標(biāo)系是第三象限,負(fù)值為向上

接下來是里面的倆小薯條了
.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);
}第二個小薯條就是三分之二的位置即可

至此 樣式完成
操作邏輯 & 效果實現(xiàn)
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以及設(shè)置配置
這里一定不能用offset系列獲取矩形屬性,因為隱藏的元素?zé)o法獲取
初始化位置
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可復(fù)用多次
現(xiàn)在有什么問題嗎??
問題大著呢,你把mouseup綁在了小按鈕上,當(dāng)你抬起位置不是按鈕,就不能觸發(fā)了
正確做法是綁定在window上
接下來是重點,滑動事件
window.addEventListener('mousemove', function (e) {
if (!moving) {
return;
}
// 圖片位置 = 鼠標(biāo)位置 - 滑動條位置 - 按鈕 / 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;
}
// 圖片位置 = 鼠標(biāo)位置 - 滑動條位置 - 按鈕 / 2 ----減去按鈕是居中
x = e.clientX - container.getBoundingClientRect().left - btn_w / 2;
btn.style.transform = `translateX(${x}px)`;
vPic.style.transform = `translate(${x}px, ${top}px)`;
});這樣基本就實現(xiàn)了,但是沒有判斷邊界呢,現(xiàn)在可以隨意滑動
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;
}
// 圖片位置 = 鼠標(biāo)位置 - 滑動條位置 - 按鈕 / 2 ----減去按鈕是居中
x = e.clientX - container.getBoundingClientRect().left - btn_w / 2;
btn.style.transform = `translateX(${x}px)`;
vPic.style.transform = `translate(${x}px, ${top}px)`;
});當(dāng)x軸小于0或者鼠標(biāo)大于圖片寬度時退出
這時候給x賦值,鼠標(biāo)抬起時判斷
window.addEventListener('mouseup', function () {
const flag = x > left - offset && x < left + offset;
moving = false;
if (flag) {
cb && cb();
}
else {
setShow(top, 'none');
}
});如果成功 執(zhí)行外面的回調(diào)函數(shù) 反之重置位置
現(xiàn)在基本完全實現(xiàn)
就在我喜出望外之際,我發(fā)現(xiàn)滑動一些刁鉆的角度,會讓鼠標(biāo)屬性改變,變成這樣
cursor: not-allowed;
因為這個原因,會擾亂事件
但是我整篇代碼也沒設(shè)置過
所以我冥思苦想
那一定是事件默認(rèn)行為搞的鬼
所以我給每個元素阻止了默認(rèn)行為,最終排查發(fā)現(xiàn),是mousedown導(dǎo)致的
btn.addEventListener('mousedown', function (e) {
// 不阻止默認(rèn)行為 會導(dǎo)致鼠標(biāo)屬性變成 `now-allowed`
e.preventDefault();
moving = true;
setShow(top, 'block');
});以上就是JavaScript實現(xiàn)滑塊補圖驗證碼效果的詳細(xì)內(nèi)容,更多關(guān)于JavaScript滑塊補圖驗證碼的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript中創(chuàng)建對象的幾種方法總結(jié)
以下幾種,是javascript中最常用的創(chuàng)建對象的方式。初學(xué)者看到后,可能會暈掉,甚至?xí)X得擔(dān)心。其實完全不用擔(dān)心,這些種方式,只需要掌握一兩種,對其他的幾種只需要理解就好了2013-11-11
基于cornerstone.js的dicom醫(yī)學(xué)影像查看瀏覽功能
這篇文章主要介紹了基于cornerstone.js的dicom醫(yī)學(xué)影像查看瀏覽功能,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07
詳解JavaScript中Hash Map映射結(jié)構(gòu)的實現(xiàn)
Hash Map通常在JavaScript中作為一個簡單的來存儲鍵值對的地方,不過哈希對象Object并不是一個真正的哈希映射,沒Java中的Hash Map來的那么強大,well,接下來帶大家詳解JavaScript中Hash Map映射結(jié)構(gòu)的實現(xiàn)2016-05-05
ES6 迭代器(Iterator)和 for.of循環(huán)使用方法學(xué)習(xí)(總結(jié))
這篇文章主要介紹了ES6 迭代器(Iterator)和 for.of循環(huán)使用方法學(xué)習(xí)總結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02
JavaScript關(guān)閉當(dāng)前頁面(窗口)不帶任何提示
這篇文章主要介紹了JavaScript關(guān)閉當(dāng)前頁面(窗口)不帶任何提示的具體實現(xiàn),需要的朋友可以參考下2014-03-03
高性能WEB開發(fā) flush讓頁面分塊,逐步呈現(xiàn) flush讓頁面分塊,逐步呈現(xiàn)
在處理比較耗時的請求的時候,我們總希望先讓用戶先看到部分內(nèi)容,讓用戶知道系統(tǒng)正在進行處理,而不是無響應(yīng)。2010-06-06

