对于一些安全性较高的网站,提供虚拟键盘功能,自己基于Ext3实现了虚拟键盘功能,所实现的功能有:
- 指定事件,当这个事件触发时,虚拟键盘显示出来,默认是focus事件
- 指定是否启用按钮位置混淆,默认是true,表示每次显示出来时,位置都不一样
- 有大小写转换开关,shift开关,控制录入字符的大小写
- 键盘自动计算显示的位置,不必担心在浏览器边上显示不全
此虚拟键盘是以插件的形式来实现的,使用起来很方便,代码如下:
/* 键盘
* author:Daniel
* createTime:2010-10-24 21:46
* usage: plugins : [keyboard]
******************************************************************************/
Ext.ux.KeyBoard = Ext.extend(Ext.ToolTip,{
wander : true,//启用按钮位置混淆
showEvents : 'focus',
boxMinWidth : 328,
boxMaxWidth : 328,
height : 103,
plain : true,
autoHide: false,
chars : {
'`':'`', '1':'!', '2':'@', '3':'#', '4':'$', '5':'%', '6':'^', '7':'&', '8':'*', '9':'(', '0':')',
'-':'_', '=':'+', ',':'<', '.':'>', '/':'?', ';':':', '\'':'"','[':'{', ']':'}', '\\':'|', '←':'←',
'Shift':'Shift', 'Caps Lock':'Caps Lock', '清空':'清空'
},
posC:['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'],
posN : ['0','1','2','3','4','5','6','7','8','9'],
init : function(field){
if(!Ext.isIE){
this.autoWidth = true;
}
this.btns = new Ext.Container({
ref : 'kbPanel',
width : Ext.isIE?318:320,
height : 103,
style : 'margin : -2px;',
layout : 'absolute',
defaults : {
width : 20
},
defaultType : 'button',
items : [{
text : "1", x : 2, y : 3 },{
text : "2", x : 25, y : 3 },{
text : "3", x : 48, y : 3 },{
text : "4", x : 71, y : 3 },{
text : "5", x : 94, y : 3 },{
text : "6", x : 117, y : 3 },{
text : "7", x : 140, y : 3 },{
text : "8", x : 163, y : 3 },{
text : "9", x : 186, y : 3 },{
text : "0", x : 209, y : 3 },{
text : "←", width : 40, x : 278, y : 3 },{
text : "Shift", ref : '../kbShift', enableToggle : true, width : 63,x : 2,y : 53 },{
text : 'Caps Lock', ref : '../kbCapsLock', enableToggle : true, width : 63 ,x : 2, y : 28 },{
text : "a", x : 68, y : 28 },{
text : "c", x : 114, y : 28 },{
text : "b", x : 91, y :28},{
text : "d", x : 137, y : 28 },{
text : "e", x : 160, y : 28 },{
text : "g", x : 206, y : 28 },{
text : "f", x : 183, y : 28 },{
text : "i", x : 252, y : 28 },{
text : "j", x : 275, y : 28 },{
text : "h", x : 229, y : 28 },{
text : "k", x : 298, y : 28 },{
text : "l", x : 68, y : 53 },{
text : "p", x : 160, y : 53 },{
text : "m", x : 91, y : 53 },{
text : "n", x : 114, y : 53 },{
text : "o", x : 137, y : 53 },{
text : "r", x : 206, y : 53 },{
text : "s", x : 229, y : 53 },{
text : "t", x : 252, y : 53 },{
text : "q", x : 183, y : 53 },{
text : "u", x : 275, y : 53 },{
text : "v", x : 298, y : 53 },{
text : "w", x : 68, y : 78 },{
text : "x", x : 45, y : 78 },{
text : "z", x : 114, y : 78 },{
text : "y", x : 91, y : 78 },{
text : "清空", ref : '../kbClear',width : 40,x : 2, y : 78 },{
text : "=", x : 255, y : 3 },{
text : "-", x : 232, y : 3 },{
text : "`", x : 137, y : 78 },{
text : "[", x : 252, y : 78 },{
text : "]", x : 275, y : 78 },{
text : ";", x : 160, y : 78 },{
text : "'", x : 183, y : 78 },{
text : ",", x : 206, y : 78 },{
text : ".", x : 229, y : 78 },{
text : "/", x : 298, y : 78
}]
});
this.add(this.btns);
this.doHandlers(field);
this.mon(this,'show',this.doWander,this);
},
doHandlers : function(field){
//给每个按钮加监听器
for(var i=0;i<this.btns.items.length;i++){
this.btns.items.get(i).on('click',function(obj){
switch(obj.text){
case 'Caps Lock':
this.doCapsLock(field);
break;
case 'Shift':
this.doShift(field);
break;
case '清空':
this.doClear(field);
break;
case '←':
this.doBackspace(field);
break;
default:
this.doClicked(obj,field);
}
},this);
}
//处理事件
field.on(this.showEvents,function(){
var posArr = field.getPosition();
var viewWidth = document.body.scrollWidth;//网页可见区宽度
var viewHeight = document.body.scrollHeight;//网页可见区高度
var posXY = [];
if((viewWidth-posArr[0]-field.getWidth()-328)>=0){
posXY.push(posArr[0]+field.getWidth());
posXY.push(posArr[1]);
}else if((viewWidth-posArr[0]-328)>=0){
posXY.push(posArr[0]);
var tmp = viewHeight-posArr[1]-field.getHeight()-103;
posXY.push(tmp>=0?(posArr[1]+this.getHeight()):(posArr[1]-103));
}else if((viewWidth-posArr[0]-328)<0){
posXY.push(posArr[0]-328);
var tmp = viewHeight-posArr[1]-field.getHeight()-103;
posXY.push(tmp>=0?(posArr[1]+this.getHeight()):(posArr[1]-103));
}else{
posXY = [posArr[0],posArr[1]+field.getHeight()];
}
this.showAt(posXY);
},this);
},
doBackspace : function(field){
var oldV = field.getValue();
var newV = oldV.substring(0,oldV.length-1);
field.setValue(newV);
},
//处理所有按钮的点击事件
doClicked : function(obj,field){
field.setValue(field.getValue() + obj.text);
},
//清除文本框的内容
doClear : function(field){
field.setValue('');
},
//点击了Shift键
doShift : function(){
this.kbShift.clicked = !this.kbShift.clicked;
var regex = /^[a-z]{1}$/i;
for(var i=0;i<this.btns.items.length;i++){
var txt = this.btns.items.get(i).text;
var ascii = txt.charCodeAt(0);
if(txt.match(regex)){//是字母
this.btns.items.get(i).setText(this.kbShift.clicked?txt.toUpperCase():txt.toLowerCase());
}else{
var tmp = this.chars[txt];
this.btns.items.get(i).setText(tmp);
delete this.chars[txt];
this.chars[tmp] = txt;
}
}
},
//点击了CapsLock
doCapsLock : function(){
//this.kbCapsLock 取得CapsLock键
var regex = /^[a-zA-Z]{1}$/;
this.kbCapsLock.clicked = !this.kbCapsLock.clicked;
for(var i=0;i<this.btns.items.length;i++){
var txt = this.btns.items.get(i).text;
if(txt.match(regex)){
this.btns.items.get(i).setText(this.kbCapsLock.clicked?txt.toUpperCase():txt.toLowerCase());
}
}
},
//混淆按钮位置
doWander : function(){
if(!this.wander){
return;
}
var regexC = /^[a-zA-Z]{1}$/;
var regexN = /^\d+$/;
var ghostC = this.posC;
var ghostN = this.posN;
for(var i=0;i<this.btns.items.length;i++){
var posxy;
var obj = this.btns.items.get(i);
if((obj.text.length == 1) && obj.text.match(regexC)){//是字母
var cIndex = OA.utils.randomNum(0,this.posC.length-1);
obj.setText(this.posC[cIndex]);
this.posC = OA.utils.arrayDelte(this.posC,cIndex);
}else if(obj.text.match(regexN)){//是数字
var nIndex = OA.utils.randomNum(0,this.posN.length-1);
obj.setText(this.posN[nIndex]);
this.posN = OA.utils.arrayDelte(this.posN,nIndex);
}
// alert(obj.text + (obj.text.length == 1) + '\t'+this.posC.length+'\t'+this.posN.length);
}
this.posC = ghostC;
this.posN = ghostN;
},
getPType : function(){
return this.ptype;
}
});
Ext.preg('keyboard',Ext.ux.KeyBoard);
插件中使用到的两个函数代码如下:
/**
* 删除数组中的一个元素,给了元素的索引即可
*
* @param {}
* index
* @return {}
*/
arrayDelte : function(arr, index) {
if (index < 0)
return arr;
return arr.slice(0, index).concat(arr.slice(index + 1, arr.length));
},
/**
* 产生从start开始到end结束的随机数字
* @param {}
* start
* @param {}
* end
*/
randomNum : function(start, end) {
return parseInt(Math.random() * (end - start + 1) + start);
}
实现的效果图如下所示: