基于jQuery的软键盘
前些天写了一个基于基于jQuery的数字键盘,今天给大家带来一个基于jQuery的全字母键盘插件(支持全字母大小写切换,数字输入,退格清除,关闭功能,可调整大小和键盘位置(可设置固定在屏幕右下角),支持鼠标和触屏拖动,并且特意保留了四个常用字符"_","-",".","/"。还有按键记忆功能哦,可自动改变使用频繁按键的背景颜色。)。
效果截图:
页面效果参照PolarBear的使用CSS3制作的苹果风格键盘 修改而成,在这里感谢PolarBear的无私分享。
一.代码分享
1.Demo页面代码
1 <ul>
2 <li><input type="text" placeholder="手机号码后四位" id="numkeyboard1" class="numkeyboard" /></li>
3 <li><input type="text" placeholder="开箱密码" id="numkeyboard2" class="numkeyboard"/></li>
4 <button type="submit"value="querun">确 认</button>
5 </ul>
键盘页面代码(插件中页面键盘的页面代码由js插入)
1 <ul id='keyboard_5xbogf8c'>
2 <li>1</li>
3 <li>2</li>
4 <li>3</li>
5 <li>4</li>
6 <li>5</li>
7 <li>6</li>
8 <li>7</li>
9 <li>8</li>
10 <li>9</li>
11 <li>0</li>
12 <li>←</li>
13 <li>Q</li>
14 <li>W</li>
15 <li>E</li>
16 <li>R</li>
17 <li>T</li>
18 <li>Y</li>
19 <li>U</li>
20 <li>I</li>
21 <li>O</li>
22 <li>P</li>
23 <li></li>
24 <li>A</li>
25 <li>S</li>
26 <li>D</li>
27 <li>F</li>
28 <li>G</li>
29 <li>H</li>
30 <li>J</li>
31 <li>K</li>
32 <li>L</li>
33 <li>Clear</li>
34 <li>CapsLock</li>
35 <li>Z</li>
36 <li>X</li>
37 <li>C</li>
38 <li>V</li>
39 <li>B</li>
40 <li>N</li>
41 <li>M</li>
42 <li><span>-</span><span>_</span></li>
43 <li><span>/</span><span>.</span></li>
44 <li>Exit</li>
45 <div id="keyboard_5xbogf8c_left"></div>
46 <div id="keyboard_5xbogf8c_right"></div>
47 </ul>
2.调用
1 $(".numkeyboard").ioskeyboard({
2 keyboardRadix:80,//键盘大小基数,实际大小比为9.4,即设置为100时实际大小为940X330
3 keyboardRadixMin:40,//键盘大小的最小值,默认为60,实际大小为564X198
4 keyboardRadixChange:true,//是否允许用户改变键盘大小,该功能仅能完美支持Chrome26;仅当keyboardRadixMin不小于60时才较好支持Safari内核浏览器
5 clickeve:true,//是否绑定元素click事件
6 colorchange:true,//是否开启按键记忆功能,如果开启,将随着按键次数的增加加深相应按键的背景颜色
7 colorchangeStep:1,//按键背景颜色改变步伐,采用RBG值,默认为RGB(255,255,255),没按一次三个数字都减去步伐值
8 colorchangeMin:154//按键背影颜色的最小值,默认为RGB(154,154,154)
9 });
3.CSS代码
#keyboard_5xbogf8c ,#keyboard_5xbogf8c li {
list-style: none;
margin: 0;
padding: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#keyboard_5xbogf8c{
position:fixed;
z-index:10;
width: 9.30em;
background: rgba(158,180,185,1);
background: -webkit-gradient(linear, 0 50%, 100% 0,from( rgba(158,180,185,1)) ,to(rgba(169,156,173,1)),color-stop(50%, rgba(222,157,193,1)));
background: linear-gradient(60deg, rgba(158,180,185,1), rgba(222,157,193,1) 50%, rgba(169,156,173,1) 100%);
padding-left: 0.1em;
border-radius: 0.05em;
padding-top: 0.1em;
box-shadow: 0 0.05em 0.1em rgba(0,0,0,.5);
display:none;
font-size:100px;
right:0.05em;
bottom:0.05em;
-webkit-text-size-adjust:none;
}
#keyboard_5xbogf8c_left{
position:absolute;
width:0.2em;
height:0.2em;
font-size:1em;
top:0em;
left:0em;
cursor:nw-resize;
}
#keyboard_5xbogf8c_right{
position:absolute;
width:0.2em;
height:0.2em;
font-size:1em;
top:0em;
right:0em;
cursor:ne-resize;
}
#keyboard_5xbogf8c ::after {
content: "";
display: table;
clear: both;
}
#keyboard_5xbogf8c li{
position:relative;
font-family: arial,"Vrinda";
width: 2.88em;
height: 2.8em;
line-height: 2.8em;
background-color: rgba(255,255,255,.8);
border-radius: 0.2em;
float: left;
text-align: center;
font-size:0.25em;
vertical-align: text-top;
margin-right: 0.4em;
margin-bottom: 0.4em;
box-shadow: 0 0.2em 0.4em rgba(0,0,0,.5);
cursor: pointer;
position: relative;
overflow:visible ;
}
#keyboard_5xbogf8c li:active {
box-shadow: inset 0 0.04em 0 rgba(0,0,0,.5);
top:0.08em;
}
#keyboard_5xbogf8c li:nth-child(11),#keyboard_5xbogf8c li:nth-child(43),#keyboard_5xbogf8c li:nth-child(22) {
background: rgba(188,188,188,.5);
font-size: 0.20em;
width: 5em;
height: 3.5em;
line-height:3.5em;
border-radius: 0.25em;
margin-right: 0.5em;
margin-bottom: 0.5em;
box-shadow: 0 0.25em 0.5em rgba(0,0,0,.5);
}
#keyboard_5xbogf8c li:nth-child(43) {
width: 3.6em;
}
#keyboard_5xbogf8c li:nth-child(12) {
margin-left: 0.96em;
}
#keyboard_5xbogf8c li:nth-child(23) {
margin-left: 1.92em;
}
#keyboard_5xbogf8c li:nth-child(22) {
width: 3.6em;
height: 4.2em;
background-color: rgba(238,238,238,1);
border-bottom-right-radius:0em;
border-bottom-left-radius:0em;
position:absolute;
top:4.5em;
right:0em;
box-shadow: inset 0 0em 0 rgba(0,0,0,.5);
}
#keyboard_5xbogf8c li:nth-child(32) {
width: 5.04em;
top:0;
background-color: rgba(238,238,238,1);
border-top-right-radius:0em;
padding-left:0.32em;
box-shadow: inset 0 0em 0 rgba(0,0,0,.5);
}
#keyboard_5xbogf8c li:nth-child(33){
font-size: 0.20em;
width: 5em;
height: 3.5em;
line-height:3.5em;
border-radius: 0.25em;
margin-right: 0.5em;
margin-bottom: 0.5em;
box-shadow: 0 0.25em 0.5em rgba(0,0,0,.5);
}
#keyboard_5xbogf8c li:nth-child(41) {
box-sizing: border-box;
padding-top: 0.6em;
}
#keyboard_5xbogf8c li:nth-child(41) span {
display: block;
line-height: 0.6;
}
#keyboard_5xbogf8c li:nth-child(42) {
box-sizing: border-box;
padding-top: 0.6em;
}
#keyboard_5xbogf8c li:nth-child(42) span {
display: block;
line-height: 0.6;
}
4.JS插件源码
/*
* ioskeyboard 1.0
* Copyright (c) 2014 BowenLuo http://www.luobo.com/
* Date: 2014-06-08
* Example:$(".numkeyboard").ioskeyboard({keyboardRadix:80,clickeve:true});
*/
(function($){
$.fn.ioskeyboard = function(options){
var defaults = {
keyboardRadix:100,//键盘大小基数,实际大小比为9.4,即设置为100时实际大小为940X330
keyboardRadixMin:60,//键盘大小的最小值,默认为30,实际大小为564X198
keyboardRadixChange:true,//是否允许用户改变键盘大小,该功能仅能完美支持Chrome26;仅当keyboardRadixMin不小于60时,完美支持Safari内核浏览器
clickeve:true,//是否绑定元素click事件
colorchange:true,//是否开启按键记忆功能,如果开启,将随着按键次数的增加加深相应按键的背景颜色
colorchangeStep:1,//按键背景颜色改变步伐,采用RBG值,默认为RGB(255,255,255),没按一次三个数字都减去步伐值
colorchangeMin:154//按键背影颜色的最小值,默认为RGB(154,154,154)
}
var options = $.extend(defaults, options);
var numkeyboardcount = 0;
var activeinputele;
var keyboardRadix = options.keyboardRadix;
var keyboardRadixMin = options.keyboardRadixMin;
var colorchange = options.colorchange;
var colorchangeStep = options.colorchangeStep;
var colorchangeMin = options.colorchangeMin;
var bMouse = false;
var bToch = false;
var MAction = false;
var MTouch = false;
var keyfixed = false;
if(keyboardRadix<keyboardRadixMin){
keyboardRadix = keyboardRadixMin;
}
this.each(function(){
numkeyboardcount++;
//添加键盘
if(numkeyboardcount<2){
$("body").append("<ul id='keyboard_5xbogf8c'>"+
"<li>1</li>"+
"<li>2</li>"+
"<li>3</li>"+
"<li>4</li>"+
"<li>5</li>"+
"<li>6</li>"+
"<li>7</li>"+
"<li>8</li>"+
"<li>9</li>"+
"<li>0</li>"+
"<li>←</li>"+
"<li>Q</li>"+
"<li>W</li>"+
"<li>E</li>"+
"<li>R</li>"+
"<li>T</li>"+
"<li>Y</li>"+
"<li>U</li>"+
"<li>I</li>"+
"<li>O</li>"+
"<li>P</li>"+
"<li></li>"+
"<li>A</li>"+
"<li>S</li>"+
"<li>D</li>"+
"<li>F</li>"+
"<li>G</li>"+
"<li>H</li>"+
"<li>J</li>"+
"<li>K</li>"+
"<li>L</li>"+
"<li>Exit</li>"+
"<li>CapsLock</li>"+
"<li>Z</li>"+
"<li>X</li>"+
"<li>C</li>"+
"<li>V</li>"+
"<li>B</li>"+
"<li>N</li>"+
"<li>M</li>"+
"<li><span>-</span><span>_</span></li>"+
"<li><span>@</span><span>.</span></li>"+
"<li>Clear</li>"+
"<div id='keyboard_5xbogf8c_left'></div>"+
"<div id='keyboard_5xbogf8c_right'></div>"+
"</ul>");
}
var inputele = $(this);
var keyboard =$("#keyboard_5xbogf8c");
var keys = keyboard.children("li");
var hiddenbutton = keyboard.children("div");
keyboard.css({"font-size":keyboardRadix+"px"});
//keyboard.css({"position":"fixed","right":"0.05em","bottom":"0.05em"});
exit();
var shiftbool = false;
if(numkeyboardcount<2){
if(options.keyboardRadixChange){
BmouseDrag();
BtouchDrag();
}
keyboard.dblclick(function(){
if(keyfixed){
keyfixed = false;
}else{
keyboard.css({"position":"fixed","right":"0.05em","bottom":"0.05em"});
keyfixed = true;
}
});
keys.click(function(event){
var keyele = $(this);
var keytext = keyele.text();
var evebool = true;
if(keytext==="CapsLock"){
activeinputele[0].focus();
if(shiftbool){
keyele.css({background:"rgba(255,255,255,.9)"});
shiftbool = false;
}else{
keyele.css({background:"rgba(188,188,188,.5)"});
shiftbool = true;
}
evebool = false;
}
if(keytext==="Exit"||keytext.length<1){
simulateKeyEvent(activeinputele[0],13);
exit();
evebool = false;
}
if(keytext==="←"){
activeinputele[0].focus();
backspace();
evebool = false;
}
if(keytext==="Clear"){
activeinputele[0].focus();
keyclear();
evebool = false;
}
if(evebool){
if(shiftbool){
if(keytext.length===2){
keytext = keytext.substring(0,1);
}
}else{
if(keytext.length===2){
keytext = keytext.substring(1,2);
}else{
keytext = keytext.toLowerCase();
}
}
clickkey(keytext);
if(colorchange){
var oldbabkground = $(this).css("background").split(',')[0].split('(')[1];
var newbabkground = oldbabkground-colorchangeStep;
if(newbabkground<colorchangeMin){
newbabkground = colorchangeMin;
alert("min")
}
$(this).css("background","rgba("+newbabkground+","+newbabkground+","+newbabkground+",.9)");
}
}
})
keyboard.children("li:eq("+21+")").mousedown(function(event){
$(this).css({top:"4.6em", "box-shadow": "inset 0 0.04em 0 rgba(0,0,0,.5)"});
keyboard.children("li:eq("+31+")").css({top:"0.1em","box-shadow": "inset 0 0em 0 rgba(0,0,0,.5)"});
})
.mouseup(function(event){
$(this).css({top:"4.5em","box-shadow":" inset 0 0em 0 rgba(0,0,0,.5)"});
keyboard.children("li:eq("+31+")").css({top:"0px","box-shadow":" inset 0 0em 0 rgba(0,0,0,.5)"});
});
keyboard.children("li:eq("+31+")").mousedown(function(event){
$(this).css({top:"0.1em","box-shadow": "inset 0 0em 0 rgba(0,0,0,.5)"});
keyboard.children("li:eq("+21+")").css({top:"4.6em", "box-shadow": "inset 0 0.04em 0 rgba(0,0,0,.5)"});
})
.mouseup(function(event){
$(this).css({top:"0px","box-shadow":" inset 0 0em 0 rgba(0,0,0,.5)"});
keyboard.children("li:eq("+21+")").css({top:"4.5em","box-shadow":" inset 0 0em 0 rgba(0,0,0,.5)"});
});
}
inputele.focus(function(event){
activeinputele = inputele;
var p = GetScreenPosition(this);
if(keyboard.css("display")=="none"){
keyboard.css({"display":"block"});
mouseDrag();
touchDrag();
}});
if(options.clickeve){
inputele.click(function(){
activeinputele = inputele;
var p = GetScreenPosition(this);
if(keyboard.css("display")=="none"){
keyboard.css({"display":"block"});
mouseDrag();
touchDrag();
}});
}
function GetScreenPosition(object) {
var position = {};
position.x = object.offsetLeft;
position.y = object.offsetTop;
while (object.offsetParent) {
position.x = position.x + object.offsetParent.offsetLeft;
position.y = position.y + object.offsetParent.offsetTop;
if (object == document.getElementsByTagName("body")[0]) {
break;
}
else{
object = object.offsetParent;
}
}
return position;
}
function keyclear(){
activeinputele.val("");
}
function backspace(){
var gbc = GetCursorPsn(activeinputele[0]);
var inputtext = activeinputele.val();
if(inputtext.length>0){
var leftstr = inputtext.substring(0,gbc);
var rightstr = inputtext.substring(gbc,inputtext.length);
leftstr = leftstr.substring(0,leftstr.length-1);
activeinputele.val(leftstr+rightstr);
setCaretPosition(activeinputele[0],gbc-1);
}
}
function clickkey(key){
var gbc = GetCursorPsn(activeinputele[0]);
var inputtext = activeinputele.val();
inputtext = strcha(inputtext,key,gbc);
activeinputele.val(inputtext);
setCaretPosition(activeinputele[0],gbc+1);
}
function exit(){
keyboard.css({"display":"none"});
}
function strcha(oldstr,ch,index){
var oldstrlength = oldstr.length;
if(oldstrlength-1<index){
return oldstr+ch;
}else{
var leftstr = oldstr.substring(0,index);
var rightstr = oldstr.substring(index,oldstrlength);
return leftstr+ch+rightstr;
}
}
function GetCursorPsn(txb) //获取输入框光标位置
{
var psn = 0;
if(txb.selectionStart) //FF
psn = txb.selectionStart;
else if(txb.selection){
var slct = document.selection; //IE
var rng = slct.createRange();
txb.select();
rng.setEndPoint("StartToStart", slct.createRange());
psn = rng.text.length;
rng.collapse(false);
rng.select();
}
return psn;
}
function setCaretPosition(elm, n) {
if(n > elm.value.length)
n = elm.value.length;
if(elm.createTextRange) { // IE
var textRange = elm.createTextRange();
textRange.moveStart('character', n);
textRange.collapse();
textRange.select();
} else if(elm.setSelectionRange) { // Firefox
elm.setSelectionRange(n, n);
elm.focus();
}
}
function BmouseDrag(){
var eventEle = hiddenbutton;
var eventEleId;
var moveEle = keyboard;
var stx = etx = curX = 0;
var keyboardfontsize = +moveEle.css("font-size").split('px')[0];
var tempsize;
eventEle.mousedown(function(event){
bMouse = true;
stx = event.pageX;
keyboardfontsize = +moveEle.css("font-size").split('px')[0];
eventEleId = $(this).attr('id');
event.preventDefault();
});
$("body").mousemove(function(event){
if(bMouse){
var curX = event.pageX-stx;
if(eventEleId==="keyboard_5xbogf8c_left"){
tempsize = keyboardfontsize-Math.ceil(curX/10);
}
if(eventEleId==="keyboard_5xbogf8c_right"){
tempsize = keyboardfontsize+Math.ceil(curX/10);
}
if(tempsize<keyboardRadixMin){
tempsize=keyboardRadixMin;
}
moveEle.css({"font-size":tempsize});
event.preventDefault();
}});
$("body").mouseup(function(event){
stx = etx = curX = 0;
bMouse = false;
});
}
function BtouchDrag() {
var eventEle = hiddenbutton;
var moveEle = keyboard;
var eventEleId;
var stx = etx = curX = 0;
var keyboardfontsize = +moveEle.css("font-size").split('px')[0];
var tempsize;
eventEle.on("touchstart", function(event) { //touchstart
var event = event.originalEvent;
bToch = true;
curX = 0;
eventEleId = $(this).attr('id');
keyboardfontsize = +moveEle.css("font-size").split('px')[0];
stx = event.touches[0].pageX;
sty = event.touches[0].pageY;
});
eventEle.on("touchmove", function(event) {
if(bToch){
var event = event.originalEvent;
curX = event.touches[0].pageX - stx;
if(eventEleId==="keyboard_5xbogf8c_left"){
tempsize = keyboardfontsize-Math.ceil(curX/10);
}
if(eventEleId==="keyboard_5xbogf8c_right"){
tempsize = keyboardfontsize+Math.ceil(curX/10);
}
if(tempsize<keyboardRadixMin){
tempsize=keyboardRadixMin;
}
moveEle.css({"font-size":tempsize});
event.preventDefault();
}
});
eventEle.on("touchend", function(event) {
stx = etx = curX = 0;
bToch = false;
})
}
function mouseDrag() {
var eventEle = keyboard;
var stx = etx = curX = sty = ety = curY = 0;
var eleRight =+eventEle.css("right").split('px')[0];
var eleBottom = +eventEle.css("bottom").split('px')[0];
eventEle.mousedown(function(event){
//console.log("down",+eventEle.css("right").split('px')[0]);
if(!keyfixed){
MAction = true;
}
//alert(MAction);
stx = event.pageX;
sty = event.pageY;
//eleRight = +eventEle.css("left").split('px')[0];
//eleBottom = +eventEle.css("top").split('px')[0];
eleRight = +eventEle.css("right").split('px')[0];
eleBottom = +eventEle.css("bottom").split('px')[0];
event.preventDefault();
});
$("body").mousemove(function(event){
if(MAction&&!bMouse){
var curX = event.pageX-stx;
var curY = event.pageY-sty;
eventEle.css({"right":eleRight-curX,"bottom":eleBottom-curY});
//console.log("move",+eventEle.css("right").split('px')[0]);
event.preventDefault();
}});
$("body").mouseup(function(event){
stx = etx = curX = sty = ety = curY = 0;
MAction = false;
//console.log("up",+eventEle.css("right").split('px')[0]);
});
}
function touchDrag() {
var eventEle = keyboard;
var stx = sty = etx = ety = curX = curY = 0;
var MTouch = false;
var eleRight = +eventEle.css("right").split('px')[0];
var eleBottom = +eventEle.css("bottom").split('px')[0];
eventEle.on("touchstart", function(event) { //touchstart
// alert(bToch);
var event = event.originalEvent;
MTouch = true;
curX = curY = 0;
// 元素当前位置
eleRight = +eventEle.css("right").split('px')[0];
eleBottom = +eventEle.css("bottom").split('px')[0];
// 手指位置
stx = event.touches[0].pageX;
sty = event.touches[0].pageY;
//console.log("up",+eventEle.css("right").split('px')[0]);
});
eventEle.on("touchmove", function(event) {
if(MTouch&&!bToch){
var event = event.originalEvent;
event.preventDefault();
curX = event.touches[0].pageX - stx;
curY = event.touches[0].pageY - sty;
//console.log("move",eleRight-curX);
//alert(eleRight+"-"+gundongX);
eventEle.css({"right":eleRight-curX,"bottom":eleBottom-curY});
}
});
eventEle.on("touchend", function(event) {
stx = etx = curX = sty = ety = curY = 0;
MTouch = false;
})
}
//模拟键盘事件,仅支持firefox,ie8-
function simulateKeyEvent(target,keyCode)
{
var customEvent = null;
var a = typeof document.createEvent;
if(typeof document.createEvent == "function"){//firefox
try {
customEvent = document.createEvent("KeyEvents");
customEvent.initKeyEvent("keypress", true, true,window, false, false, false, false, keyCode, keyCode);
target.dispatchEvent(customEvent);
} catch (ex){
//console.log("This example is only demonstrating event simulation in firefox and IE.");
}
} else if (document.createEventObject){ //IE
customEvent = document.createEventObject();
customEvent.bubbles = true;
customEvent.cancelable = true;
customEvent.view = window;
customEvent.ctrlKey = false;
customEvent.altKey = false;
customEvent.shiftKey = false;
customEvent.metaKey = false;
customEvent.keyCode = keyCode;
target.fireEvent("onkeypress", customEvent);
}
else {
//console.log("This example is only demonstrating event simulation in firefox and IE.");
}
}
});
};
})(jQuery);
二.实现探讨
1.元素布局和样式
布局没啥好说的,一个按键一个li元素或div等元素(仿回车键我用了俩个li,如果大小不是确定的,这样可能会出现一些问题,所以没有必要还是不要用),浮动float:left,再用一个父元素包裹起来。
css上主要用box-shadow结合active来实现按键动作的视觉效果,比较少用的可能是user-select: none消除元素的选中效果(默认为蓝色遮罩),还有特别漂亮的渐变背景效果linear-gradient。特别要讲到的是除了父元素的font-size外全部采用em作为单位,这也是做的好处就是只有改变父元素的font-size就可以比例改变所有元素的大小,缺点就是部分浏览器(如chrome)支持的font-size的最小值为12px,所以缩放有一定的限制,需要根据最底层的font-size值来设置最小值。解决方案就是把所有文字全部单独包裹放在每个层的最底层,把字体大小和元素大小独立起来。
2.js实现
a.如果要用js插入键盘html代码,必须确保一个页面只插入一次。
b.键盘的拖动:监听键盘元素上的mousedown事件,当鼠标在键盘上按下时记录鼠标的位置,当鼠标移动时根据鼠标当前的位置与鼠标按下是的位置差来确定移动的距离,同步改变键盘元素的位置。触屏拖动与此类似。
c.改变键盘大小:上面讲到过,要比例改变键盘大小,只要改变键盘元素的font-size值即可。所以只需要添加事件来触发就行了,这里是添在键盘的左右上角分别添加了一个透明元素,当在触发此元素上的mousedown事件时根据鼠标拖动的水平距离来比例改变font-size值。
d.按键事件:监听每个按键元素的click事件。根据按键的text来确定按下的是哪个键(也可以用index()来判断),然后做出相应的动作。例如在输入框中写入按键值,大小写切换,退格,清除,关闭键盘等。
e.键盘按键记忆功能:纯属无聊才加了这个功能,大家不必在意。实现的方法就是每按一个键,就把这个按键的背景元素rgb全部减去一个常量,直到设定的最小值。所以效果只是简单的白-灰-黑。如果把rgb分开改变的话,效果会更丰富。
f.事件键盘模拟事件:模拟实际键盘按下确认键后自动提交的功能,按下Exit后自动提交。由于浏览器的限制,该功能目前只在firefox中测试通过,据说ie8及以下的浏览器都可以,不过没有太大的意义。
必较重要的是键盘的每个事件在一个页面内最好是确保只会监听一次,因为事件监听几次触发的时候就会执行几次,如果这样的话,就可能达不到预计效果。例如如果键盘按键的click事件,如果监听多次的话,每一次按键都会在输入框中输入几个键值。