微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用node.js生成后端可以拖动的拼图验证码

使用npm包canvas在后端绘制一张背景图片,然后在这张背景图片截取一部分作为拼图,让用户移动拼图到正确的位置,同时将此拼图所截取的区域用一个空白的区域覆盖。

import express from 'express';

const Canvas = require('canvas');
const path = require('path');

const router = express.Router();

// 背景图片的宽可以传参设置,认值是320 * 180,小拼图认是60 * 45
router.get('/drag_captcha',(req,res) => { const { bgWidth: width } = req.query; const bgWidth = parseInt(width) || 320; const bgHeight = (width && parseInt(width * 180 / 320)) || 180; const dragPicWidth = 60; const dragPicHeight = 45; const index = Math.floor(Math.random() * 13); const positionX = Math.floor(Math.random() * (bgWidth - dragPicWidth - 10) + 11); // 空白拼图的定位X const positionY = Math.floor(Math.random() * (bgHeight - dragPicHeight - 10) + 11); const Image = Canvas.Image; const bgCanvas = new Canvas(bgWidth,bgHeight); const dragCanvas = new Canvas(dragPicWidth,dragPicHeight); const background = bgCanvas.getContext('2d'); const dragPic = dragCanvas.getContext('2d'); const image = new Image(); image.onload = () => { background.drawImage(image,0,320,180,bgWidth,bgHeight); dragPic.drawImage(bgCanvas,positionX,positionY,dragPicWidth,dragPicHeight,dragPicHeight); background.clearRect(positionX,dragPicHeight); }; image.src = path.join(__dirname,`../app/assets/images/validate/bg-${index}.png`); if (req.session) { req.session.dragCaptcha = { positionX,positionY }; } res.send({ bgCanvas: bgCanvas.toDataURL(),dragCanvas: dragCanvas.toDataURL() }); }); router.post('/check_captcha_position',res) => { const { offsetLeft,offsetTop } = req.body; const { dragCaptcha = {} } = req.session; const range = 5; // 误差范围 if (!offsetLeft || !offsetTop) return; console.log(dragCaptcha.positionX,dragCaptcha.positionY); const deviationX = Math.abs(offsetLeft - dragCaptcha.positionX); const deviationY = Math.abs(offsetTop - dragCaptcha.positionY); if (deviationX < range && deviationY < range) { res.send({ error: false }); } else { res.send({ error: true }); } }); export default router; 

在前端页面加载后生成背景图片和拼图,当移动拼图时判断拼图的正确位置。在这里,把它封装为在普通JS或者node.js都可以加载实现的文件。注意,在PC端鼠标按下拖动事件是mousedown,mousemove,mouseup,对应的移动端事件是touchstart,touchmove,touchend

(function(factory) { if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = factory(); } else { window.DragCaptcha = factory(); } })(function () { var extend = { addEventListener: function(target,type,handler) { var obj = target === 'document' ? document : target; try { obj.addEventListener(type,handler,false); } catch (error) { obj.attachEvent('on' + type,handler); } },removeEventListener: function(target,handler) { var obj = target === 'document' ? document : target; try { obj.removeEventListener(type,false); } catch (error) { obj.detachEvent('on' + type,handler); } } }; /** * DragCaptcha * @param targetId 添加到指定id的节点中 * @param callback 拖动时松开鼠标后的回调函数 * @param bgWidth 背景图片的宽度(不加单位px) */ function DragCaptcha(targetId,callback,bgWidth) { this.targetId = targetId; this.callback = callback; this.bgWidth = bgWidth; this.bgHeight = bgWidth * 180 / 320; this.hasAddedEvent = false; this.defaultValue = { bgWidth: '320px',bgHeight: '180px',dragWidth: '60px',dragHeight: '45px' }; this._init(); } DragCaptcha.prototype = { constructor: DragCaptcha,_init: function () { this.createElement(); this.getimage(this.bgWidth); },appendHtml: function(targetId,child) { var target = document.getElementById(targetId); target.appendChild(child); },createElement: function() { var canvasWrapper = document.createElement('div'); canvasWrapper.style.position = 'relative'; canvasWrapper.style.width = this.bgWidth ? this.bgWidth + 'px' : this.defaultValue.bgWidth; canvasWrapper.style.margin = '5px auto'; var bgImage = document.createElement('img'); bgImage.setAttribute('id','bg-canvas'); bgImage.style.width = this.bgWidth ? this.bgWidth + 'px' : this.defaultValue.bgWidth; bgImage.style.height = this.bgHeight ? this.bgHeight + 'px' : this.defaultValue.bgHeight; var dragImage = document.createElement('img'); dragImage.setAttribute('id','drag-canvas'); dragImage.style.position = 'absolute'; dragImage.style.top = 0; dragImage.style.left = 0; dragImage.style.width = this.defaultValue.dragWidth; dragImage.style.height = this.defaultValue.dragHeight; var tip = document.createElement('div'); tip.innerHTML = '请拖动拼图填充完整图片'; canvasWrapper.appendChild(bgImage); canvasWrapper.appendChild(dragImage); this.appendHtml(this.targetId,canvasWrapper); this.appendHtml(this.targetId,tip); },getimage: function(bgWidth) { var that = this; var xhr = new XMLHttpRequest(); var response; var bgImage = document.querySelector('img#bg-canvas'); var dragImage = document.querySelector('img#drag-canvas'); xhr.open('get','/drag_captcha?bgWidth=' + bgWidth); xhr.send(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { response = JSON.parse(xhr.responseText); dragImage.style.left = 0; dragImage.style.top = 0; bgImage.src = response.bgCanvas; dragImage.src = response.dragCanvas; if (that.hasAddedEvent) return; that.hasAddedEvent = true; that.drag(); } } },drag: function() { var that = this; var bgImage = document.querySelector('img#bg-canvas'); var dragImage = document.querySelector('img#drag-canvas'); var moveMaxValueX = bgImage.width - dragImage.width; // 水平方向最大移动距离 var moveMaxValueY = bgImage.height - dragImage.height; // 垂直方向最大移动距离 var dragStartX = dragImage.offsetLeft; // 拼图初始水平位置 var dragStartY = dragImage.offsetTop; // 拼图初始垂直位置 if (/Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { extend.addEventListener(dragImage,'touchstart',function(e) { if (e.preventDefault) { e.preventDefault(); } else { window.event.returnValue = false; } var startClientX = e.targettouches[0].pageX; var startClientY = e.targettouches[0].pageY; var dragMoveLeft = dragImage.offsetLeft; var dragMovetop = dragImage.offsetTop; var fnMouseMove = function(e) { var mouseMoveX = e.targettouches[0].pageX - startClientX; var mouseMoveY = e.targettouches[0].pageY - startClientY; var toX = dragMoveLeft + mouseMoveX; var toY = dragMovetop + mouseMoveY; if (toX > moveMaxValueX) { toX = moveMaxValueX; } else if (toX < dragStartX) { toX = dragStartX; } if (toY > moveMaxValueY) { toY = moveMaxValueY; } else if (toY < dragStartY) { toY = dragStartY; } dragImage.style.left = toX + 'px'; dragImage.style.top = toY + 'px'; }; extend.addEventListener(document,'touchmove',fnMouseMove); var fnMouseUp = function() { extend.removeEventListener(document,fnMouseMove); extend.removeEventListener(document,'touchend',fnMouseUp); that.callback && that.callback(); } extend.addEventListener(document,fnMouseUp); }); return; } extend.addEventListener(dragImage,'mousedown',function(e) { if (e.preventDefault) { e.preventDefault(); } else { window.event.returnValue = false; } var startClientX = e.clientX; var startClientY = e.clientY; var dragMoveLeft = dragImage.offsetLeft; var dragMovetop = dragImage.offsetTop; var fnMouseMove = function(e) { var mouseMoveX = e.clientX - startClientX; var mouseMoveY = e.clientY - startClientY; var toX = dragMoveLeft + mouseMoveX; var toY = dragMovetop + mouseMoveY; if (toX > moveMaxValueX) { toX = moveMaxValueX; } else if (toX < dragStartX) { toX = dragStartX; } if (toY > moveMaxValueY) { toY = moveMaxValueY; } else if (toY < dragStartY) { toY = dragStartY; } dragImage.style.left = toX + 'px'; dragImage.style.top = toY + 'px'; }; extend.addEventListener(document,'mousemove','mouseup',fnMouseUp); }); } }; return DragCaptcha; });

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐