這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 不知各位朋友現在在web端進行登錄的時候有沒有註意一個變化,以前登錄的時候是直接賬號密碼通過就可以直接登錄,再後來圖形驗證碼,數字結果運算驗證,到現在的拼圖驗證。這一系列的轉變都是為了防止機器操作,但對於我們來說,有億點麻煩,但也沒 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前言
不知各位朋友現在在web
端進行登錄的時候有沒有註意一個變化,以前登錄的時候是直接賬號密碼通過就可以直接登錄,再後來圖形驗證碼,數字結果運算驗證,到現在的拼圖驗證。這一系列的轉變都是為了防止機器操作,但對於我們來說,有億點麻煩,但也沒辦法呀。
今天我們也一起來做一個製造億點麻煩的人,實現一個拼圖驗證。
實現原理
這個實現原理並不複雜,我們只需要一張圖作為我們的拼接素材,我們再單獨弄一個盒子,然後移動它,到我們的指定位置,到達指定範圍內即驗證通過,反之驗證未通過。
既然原理我們知道了,那我們就開乾吧。
實現前端登錄拼圖驗證
本篇文章以 css
為主, javascript
為輔實現。
搭建框架
我們要實現這個功能,我們需要先搭建出來一個框架。
// css <style> .check{ width: 400px; height: 300px; background-repeat: no-repeat; background-size: 100% 100%; background-image: url(https://img0.baidu.com/it/u=2028084904,3939052004&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500); } </style> // html <div class="check"></div>
我們畫出來後,它就長下麵圖這樣。
添加被校驗區域及校驗區域
我們需要添加一個被校驗的區域及校驗區域,用來做我們的校驗,像下圖這兩個東西。
這裡我們使用偽類來實現這兩個區域。
校驗區域
.check::before{ content: ''; width: 50px; height: 50px; background: rgba(0, 0, 0, 0.5); border: 1px solid #fff; position: absolute; top: 100px; left: 280px; }
這樣一個校驗區域就做好了。
被校驗區域
這裡我們需要使用到background-position
根據我們的校驗區域大小進行切出我們的被校驗區域。
background-image
和background-repeat
我們直接繼承,background-position
設置為校驗區域的坐標位置(也就是距離top
和left
的距離),我們將background-size
圖片大小設為原盒子的大小。這樣我們就得到了校驗區域的那一片區域,也就是我們的被校驗區域了。
.check-child{ content: ''; width: 50px; height: 50px; border: 1px solid #fff; background-image: inherit; background-repeat: inherit; background-size: 400px 300px; background-position: -280px -100px; position: absolute; top: 100px; left: 10px; } // html <!-- 被校驗區域 --> <div class="check-child"></div>
添加拖動條
這裡我們兩個區域都添加完了,我們需要添加一個拖動條。
我們先添加一個拖動區域。
// css .drag{ width: 400px; height: 50px; background-color: #e3e3e3; margin-top: 10px; position: relative; } // html <div class="drag"></div>
現在拖動區域有了,我們需要在拖動區域內添加一個可拖動的盒子,及操作說明,不然看起來交互效果不友好。
添加可拖動的盒子及交互說明
我們添加一個可以拖動的盒子。
// css .drag-child{ width: 50px; height: 50px; background-color: aquamarine; z-index: 10; position: absolute; top: 0; left: 0; } // html <!-- 可拖動的盒子 --> <div class="drag-child"></div>
為了我們友好的交互,我們在拖動區域內給他添加操作說明。
// css .drag-tips{ display: flex; align-items: center; justify-content: end; width: 95%; height: 100%; margin: 0 auto; font-size: 12px; color: #8a8a8a; } // html <!-- 可拖動的盒子 --> <div class="drag-tips"> <span>按住左邊按鈕向右拖動完成上方圖像驗證</span> </div>
拖動條動起來
這一步我們需要讓我們的拖動盒子動起來,讓他可以在拖動區域內隨意的左右拖動。
// 獲取元素實例 const drag = document.querySelector('.drag-child') // 聲明滑鼠按下事件 const dragMouseDown = event => { // 添加滑鼠移動事件 document.addEventListener('mousemove', dragMouseMove) } // 監聽滑鼠移動事件 const dragMouseMove = event => { // 獲取當前 x 軸坐標 const { offsetX } = event if(offsetX < 0 || offsetX > 350){ return } // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${offsetX}px)` } // 結束滑鼠監聽事件 const dragMouseUP = event => { // 移除滑鼠移動事件 document.removeEventListener('mousemove', dragMouseMove) } // 添加滑鼠按下事件 document.addEventListener('mousedown', dragMouseDown) // 添加滑鼠彈起事件 document.addEventListener('mouseup', dragMouseUP)
現在我們的盒子就可以正常的拖動了,但現在它還有幾個問題,我們後面來解決。
- 提示文字會被選中;
- 在
拖動區域
內拖動會閃爍;
聯動被校驗區域
我們先讓被校驗區域跟著我們的拖動動起來。
// 圖形校驗 const check = document.querySelector('.check-child') // 修改被校驗區域坐標 check.style.left = `${offsetX}px`
這樣我們的被校驗區域就能夠跟著動了,我們聲明一個方法用來表示,通過校驗的回調。
// 通過校驗回調 const success = () => { console.log('通過校驗'); } // 監聽滑鼠移動事件 const dragMouseMove = event => { // 獲取當前 x 軸坐標 const { offsetX } = event if(offsetX < 0 || offsetX > 350){ return } // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${offsetX}px)` // 修改被校驗區域坐標 check.style.transform = `translateX(${offsetX}px)` if(offsetX >= 278 && offsetX <= 285){ // 執行回調 success() } }
添加交互動畫
這裡我們在滑鼠移出監聽的時候添加一個動畫,噹噹前未通過校驗的時候我們給他還原到初始位置。
@keyframes move { to { transform: translateX(0); } }
// 結束滑鼠監聽事件 const dragMouseUP = event => { // 移除滑鼠移動事件 document.removeEventListener('mousemove', dragMouseMove) // 獲取當前 x 軸坐標 const { offsetX } = event if(offsetX < 278 || offsetX > 285){ // 修改可移動盒子的 x 軸坐標 drag.style.animation = 'move 0.5s ease-in-out' // 修改被校驗區域坐標 check.style.animation = 'move 0.5s ease-in-out' // 動畫結束監聽回調 const animationEnd = ()=>{ // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${0}px)` // 修改被校驗區域坐標 check.style.transform = `translateX(${0}px)` // 清除動畫屬性 drag.style.animation = '' check.style.animation = '' // 移出動畫結束監聽 document.removeEventListener("animationend", animationEnd) } // 添加動畫結束監聽 document.addEventListener("animationend", animationEnd) } }
當我們未通過校驗,且放開滑鼠的時候,它就會自動回到初始位置。
解決遺留問題
1、 提示文字會被選中
我們在提示文字的樣式中添加user-select: none;
,禁用掉文字選擇。
/* 提示文字說明 */ .drag-tips{ display: flex; align-items: center; justify-content: end; width: 95%; height: 100%; margin: 0 auto; font-size: 12px; color: #8a8a8a; user-select: none; z-index: 1; position: absolute; top: 0; left: 0; }
2、 在拖動區域
內拖動會閃爍
我們將我們剛剛使用的offsetX
改為pageX
。這裡需要註意一下邊距偏移量的問題哦。
// 監聽滑鼠移動事件 const dragMouseMove = event => { console.log(event); // 獲取當前 x 軸坐標 const { pageX } = event if(pageX < 0 || pageX > 350){ return } // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${pageX}px)` // 修改被校驗區域坐標 check.style.transform = `translateX(${pageX}px)` if(pageX >= 278 && pageX <= 285){ // 執行回調 success() } } // 結束滑鼠監聽事件 const dragMouseUP = event => { // 移除滑鼠移動事件 document.removeEventListener('mousemove', dragMouseMove) // 獲取當前 x 軸坐標 const { pageX } = event if(pageX < 278 || pageX > 285){ // 修改可移動盒子的 x 軸坐標 drag.style.animation = 'move 0.5s ease-in-out' // 修改被校驗區域坐標 check.style.animation = 'move 0.5s ease-in-out' // 動畫結束監聽回調 const animationEnd = ()=>{ // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${0}px)` // 修改被校驗區域坐標 check.style.transform = `translateX(${0}px)` // 清除動畫屬性 drag.style.animation = '' check.style.animation = '' // 移出動畫結束監聽 document.removeEventListener("animationend", animationEnd) } // 添加動畫結束監聽 document.addEventListener("animationend", animationEnd) } }
效果圖
我們看一下效果圖。
完整代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>drag</title> <style> *{ margin: 0; padding: 0; } body{ padding: 20px; } /* 圖形拼圖驗證碼 */ .check{ width: 400px; height: 300px; background-repeat: no-repeat; background-size: 100% 100%; background-image: url(https://img0.baidu.com/it/u=2028084904,3939052004&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500); position: relative; } .check::before{ content: ''; width: 50px; height: 50px; background: rgba(0, 0, 0, 0.5); border: 1px solid #fff; position: absolute; top: 100px; left: 280px; } .check-child{ content: ''; width: 50px; height: 50px; border: 1px solid #fff; background-image: inherit; background-repeat: inherit; background-size: 400px 300px; background-position: -280px -100px; position: absolute; top: 100px; left: 0; } /* 拖動條 */ .drag{ width: 400px; height: 50px; background-color: #e3e3e3; margin-top: 10px; position: relative; } /* 可拖動的盒子 */ .drag-child{ width: 50px; height: 50px; background-color: aquamarine; z-index: 10; position: absolute; top: 0; left: 0; } /* 提示文字說明 */ .drag-tips{ display: flex; align-items: center; justify-content: end; width: 95%; height: 100%; margin: 0 auto; font-size: 12px; color: #8a8a8a; user-select: none; z-index: 1; position: absolute; top: 0; left: 0; } @keyframes move { to { transform: translateX(0); } } </style> </head> <body> <!-- 圖形校驗區域 --> <div class="check"> <!-- 被校驗區域 --> <div class="check-child"></div> </div> <!-- 拖動條 --> <div class="drag"> <!-- 操作說明 --> <div class="drag-tips"> <span>按住左邊按鈕向右拖動完成上方圖像驗證</span> </div> <!-- 可拖動的盒子 --> <div class="drag-child"></div> </div> </body> <script> // 獲取元素實例 const drag = document.querySelector('.drag-child') // 圖形被校驗區域 const check = document.querySelector('.check-child') // 通過校驗回調 const success = () => { console.log('通過校驗'); } // 聲明滑鼠按下事件 const dragMouseDown = event => { // 添加滑鼠移動事件 document.addEventListener('mousemove', dragMouseMove) } // 監聽滑鼠移動事件 const dragMouseMove = event => { // 獲取當前 x 軸坐標 const { pageX } = event if(pageX < 0 || pageX > 350){ return } // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${pageX}px)` // 修改被校驗區域坐標 check.style.transform = `translateX(${pageX}px)` if(pageX >= 278 && pageX <= 285){ // 執行回調 success() } } // 結束滑鼠監聽事件 const dragMouseUP = event => { // 移除滑鼠移動事件 document.removeEventListener('mousemove', dragMouseMove) // 獲取當前 x 軸坐標 const { pageX } = event if(pageX < 278 || pageX > 285){ // 修改可移動盒子的 x 軸坐標 drag.style.animation = 'move 0.5s ease-in-out' // 修改被校驗區域坐標 check.style.animation = 'move 0.5s ease-in-out' // 動畫結束監聽回調 const animationEnd = ()=>{ // 修改可移動盒子的 x 軸坐標 drag.style.transform = `translateX(${0}px)` // 修改被校驗區域坐標 check.style.transform = `translateX(${0}px)` // 清除動畫屬性 drag.style.animation = '' check.style.animation = '' // 移出動畫結束監聽 document.removeEventListener("animationend", animationEnd) } // 添加動畫結束監聽 document.addEventListener("animationend", animationEnd) } } // 添加滑鼠按下事件 document.addEventListener('mousedown', dragMouseDown) // 添加滑鼠彈起事件 document.addEventListener('mouseup', dragMouseUP) </script> </html>