请选择 进入手机版 | 继续访问电脑版
赛鸥桌面 设为首页收藏本站赛鸥提示:

 找回密码
 加入赛欧

QQ登录

只需一步,快速开始

搜狗专业排名,10页前可做!接快速排名,强进百度首页(上后付)云香港美国空间免费试用~另接仿站淘宝天猫免费领取大额优惠券
查看: 559|回复: 0

[原创] JavaScript模拟实现12306图片验证码 [复制链接]

Rank: 2

升级 
 
18.57%
威望
13 点
鸥币
14 枚
贡献
23 点
赛币
0 枚
注册时间
2012-10-26
发表于 2017-1-5 14:21:53 |显示全部楼层
看帖容易编辑难!赛欧提示您:做人要厚道、看帖要回帖,好贴不评分、大家鄙视你!
看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

您需要登录后才可以回帖 登录 | 加入赛欧

关闭

赛鸥推荐内容

WordPress评论群发工具WPsBoxPro
WPsBoxPro是一款针对Wordpress系统群发评论的工具,他的功能基本都是从SB分割出来的,所以不建议大家购买,破解版WPsBoxPro大家可以用用...

查看 »

赶快加入赛欧免费学习英文SEO吧!QQ直接登录一步搞定...

关于赛鸥|服务范围|联系我们|手机版|Archiver|英文seo 淘宝客

GMT+8, 2019-3-25 17:51 , Processed in 0.035483 second(s), 17 queries .

Powered by 赛鸥网络营销知识社区

© 2009-2012 赛鸥站长网

回顶部