找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2700|回复: 0

[探讨] JavaScript模拟实现12306图片验证码

  [复制链接]
发表于 2017-1-5 14:15:13 | 显示全部楼层 |阅读模式 来自 中国–福建–厦门
看12306的图片验证码挺好玩的,拿起js我也来实现一个。
既然是验证码就有显示,输入和验证三个过程
1、显示
12306的图片验证码是把一些小图显示在一张大图上,为了实现这个,我去网上找了一些图片,把同一类别的图片放在一个文件夹下面,根据序号依次命名,这个步骤做完就只需要建立索引数组,标记物体名(文件夹以物体名命名)和物体总图片个数,这样子我们就可以从中随记冲去任意一个物体的任意一张图片。
2、输入
输入就是点击图片时会插入的那些笔记小图标啦,对于这些小图标,需要记录下它相对于大图的偏移坐标作为后期验证的依据。
3、验证
验证的过程需要从生成图片的时候就开始了,首先我们会从索引数组中抽取任意张图片(在这里8张)形成一个图片数组,打乱数组的顺序,然后将图片依次画到大图上面去,在这里使用的是canvas,在画小图的过程中,根据显示的偏移量生成验证数组,最后将我们点选图片不同位置时生成的便宜坐标拿过来以此和验证数组进行比对。在这里有一个问题,就是只有点选的坐标数等于验证数组的长度才进行比对,如果长度不一样,那输入肯定是错的。
代码实现:
;(function(){
var Code = (function(){
var canvas,ctx,W,H,picWidth,gap,codeInfo,vCode = [],sources = {};
var init = function(){
W = 293;
H = 190;
var codeContainer = document.createElement("div");
codeContainer.style.cssText=";width:"+W+"px;height:"+H+"px;position:relative;";
codeContainer.id = "codeContainer";
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
picWidth = 70;
gap = 3;
canvas.width = W;
canvas.height = H;
codeContainer.appendChild(canvas);
document.body.appendChild(codeContainer);
sources = [
{ "name" : "ant" ,"title" : "蚂蚁" , "count" : 2},
{ "name" : "bee" ,"title" : "蜜蜂" , "count" : 2},
{ "name" : "fan" ,"title" : "电风扇" , "count" : 1},
{ "name" : "flower" ,"title" : "花儿" , "count" : 2},
{ "name" : "hopper" ,"title" : "蚂蚱" , "count" : 2}
];
generateCode();
createRefreshButton();
}
var generateCode = function(){
clear();
codeInfo = getTarget();
var pics = getPics();
drawTitle(codeInfo.title);
particlePics(pics);
}
var createRefreshButton = function(){
var d = document.createElement("div");
d.className = 'refresh';
canvas.parentNode.appendChild(d);
}
var drawTitle = function(name){
var pre = "请点击下图中",middle = "所有的";
ctx.fillStyle = "#000";
ctx.font = "16px Arial";
ctx.fillText(pre,2,16);
ctx.fillStyle = "#f00";
ctx.fillText(middle,textWidth(pre,16)+rand(1,3),16);
ctx.fillStyle = randC();
ctx.font = "20px Arial";
ctx.fillText(name,textWidth(pre+middle,16)+rand(2,5),16);
drawLine();
}
var drawLine = function(){
ctx.beginPath();
ctx.moveTo(0,25);
ctx.lineTo(W,25);
ctx.stroke();
}
var getPics = function(){
var codeCount = Math.round(Math.random()*(codeInfo.count<8?codeInfo.count:8)),itemArr = [],extraArr = [],pics = [];
codeCount = codeCount ? codeCount: codeCount + 1;
var extraCount = 8 - codeCount;
for(var i=0;i<codeInfo.count;i++){
var src = "images/"+ codeInfo.name + "/" + (i+1) +".jpg";
var im  = new Image();
im.src = src;
itemArr.push({
'img' : im,
'name' : codeInfo.name
});
}
while(codeCount>0){
var index = Math.floor(Math.random()*itemArr.length),src = itemArr[index];
pics.push(src);
itemArr.splice(index,1);
codeCount--;
}
for(var index in sources){
var item = sources[index];
if(item.name!=codeInfo.name){
for(var i=0;i<item.count;i++){
var src = "images/"+ item.name + "/" + (i+1) +".jpg";
var im  = new Image();
im.src = src;
extraArr.push({
'img' : im,
'name' : item.name
});
}
}
}
while(extraCount>0){
var index = Math.floor(Math.random()*extraArr.length),src = extraArr[index];
pics.push(src);
extraArr.splice(index,1);
extraCount--;
}
return pics;
}
var particlePics = function(pics){
var pics = randArray(pics);
for(var i=0,l=pics.length;i<l;i++){
(function(i){
var item = pics[i],im = item.img,x = (i%4)*(picWidth+gap),y=((i/4)>>0)*(picWidth+gap)+35;
if(item.name===codeInfo.name){
vCode.push({
'x' : x,
'y' : y
})
}
im.onload = function(){
ctx.drawImage(im,x,y);
}
})(i);
}
}
var verify = function(select,callback){
var len = vCode.length;
callback && callback();
if(select.length!==len){
alert("验证失败!");
reload();
return;
}
var count = 0;
for(var i=0,l=select.length;i<l;i++){
var item = select[i];
vCode.map(function(row){
if(item.x>=row.x&&item.x<=row.x+picWidth&&item.y>=row.y&&item.y<=row.y+picWidth){
count++;
}
})
}
if(count!==len){
alert("验证失败!");
reload();
return;
}else{
alert("验证成功!");
reload();
return;
}
}
var reload = function(){
vCode.length = 0;
generateCode();
}
var clear = function(){
ctx.clearRect(0,0,W,H);
}
var getTarget = function(){
return sources[Math.floor(Math.random()*sources.length)];
}
var textWidth = function(string,size){
ctx.font = size + "px Arial";
return ctx.measureText(string).width;
}
var rand = function(min,max){
return Math.random() * (max - min) + min;
}
var randC = function(){
return "rgb(" + ((Math.random() * 255)>>0) + "," + ((Math.random() * 255)>>0) + "," +((Math.random() * 255)>>0) +")";
}
var randArray = function(arr){
return arr.sort(function(a,b){
return Math.random()>0.5?true:false;
});
}
return {
init : init,
verify : verify,
reload : reload
}
})();
window.Code = window.Code || Code;
})();
在线实例:http://www.llsffx.com


发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;

如何回报帮助你解决问题的坛友,好办法就是点击帖子下方的评分按钮给对方加【金币】不会扣除自己的积分,做一个热心并受欢迎的人!

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 需要先绑定手机号

关闭

站长推荐上一条 /1 下一条

QQ|侵权投诉|广告报价|手机版|小黑屋|西部数码代理|飘仙建站论坛 ( 豫ICP备2022021143号-1 )

GMT+8, 2024-11-22 20:59 , Processed in 0.045590 second(s), 9 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表