您的位置:首页 > Web前端 > JQuery

基于jquery实现表格中的上下左右键切换input的焦点

2011-09-26 16:47 423 查看
  前段时间在项目中遇到一个表格中要批量录入非常多的数据,鼠标键盘操作令人眼花缭乱,顿有想法要做个利用键盘的上下左右键切换输入框焦点的小插件。

  要实现的功能为:

    上键:焦点到上一行相同列的input,

    下键:焦点到下一行相同列的input,

    左键:焦点到本行左边相邻的input,

    右键:焦点到本行右边相邻的input

  当然这里说的input都在一个table中的所有的input。既然是要通过键来实现,我只能想到通过keydown的事件来处理了,通过测试,那个几个键的code分别为:

上键:38,下键:40,左键:37,右键:39.当keycode等于这几个值时我就进行处理,这里用switch行,用if,esle也可以,我比较喜欢用后者

  比较关键的地方是要找到按键后焦点该去哪个input。 如果利用jquery,首先会想到的就是查找父元素中的符合条件的input的下一个,在同一个tr中这个比较好找,但如果当前元素是本行的最后一个,如果输入右键,焦点应该跳到下一行的第一个inpput,这时候就麻烦了。并且如果单纯的利用dom就那样find来find去,很难达到目的。

  上下键的切换只要找到input间相对应的index就可以了。中间本来想通过input所在的单元格的索引来查找查找上行或者下行的同列的单元格中的input,但通过parents查找的td总是与通过tr>td中超找的相对应的td不相等,利用chome调试只有选择器有区别,其他属性都一致,可就是用index方法找不出来,始终是-1...此路就此终结

  不得不采用终极解决方案:在input上加属性,存储他是第几行第几列,到时直接取出,去找上下行的第几列就得了,所以在遍历的符合条件的input时加上这句

  

$(this).attr("_r_", inputRowIndex).attr("_c_", j);


  inputRowIndex为行的索引,j为列的索引.

  现在就要考虑每次要从哪去查找那些input,如果通过jquery的dom去找,每次keydown都去find,效率自然会比较低,为什么低不太好解释。这里显然用变量来存储所有的input会高效些。但又如何实现很方便的查找呢?

  比较自然的我就会想到构造一个table那样的立体结构来存储,一行一行的保存,并且都是按顺序的存储,并且我能在每个元素上取到我想要的东西,比如当前元素是第几行,第几列。我能很方便的获取数据,比如我传递第几行,第几列过去就能很方便的获取对应的input。这两样东西js都有现成的了,第一个用json,第二个,嘿嘿,非数组不能那样方便高效的获取数据了,于是我定义出如下数据格式

var rowInputs = [
[
{ "length": len, //当前行有多少个input
"rowindex":row, //当前行在所有数据行中的索引
“data”:[   //input集合
{ "c": j, "input": this } //单个input元素,c为列
。。。。
]}
。。。。
]
。。。
]; //所有的input集合,一个元素为一个tr中的所有的input


  这样我能比较方便的找到当前元素的第几行,第几列,然后根据keycode来计算要获得焦点的input:(查看了排版,源代码还是直接在下面看好了)

见下完整代码


  

$(rowInputs[r].data[c].input).focus();为设置焦点

好了,大概就这么多了吧。
不过后面还要注意的是,如果要通用到所有的项目中,那么应该考虑隐藏的,只读的情况,那些input都不赢考虑在内
经实际测试,有一行数据都是只读的,所有出现那样的情况,应该整行数据都抛弃:


var thisRowInputs;
if (!inputType) { //所有的input
thisRowInputs = $(obj).find("input:not(:disabled):not(:hidden):not([readonly])");
} else {
thisRowInputs = $(obj).find("input:not(:disabled):not(:hidden):not([readonly])[type=" + inputType + "]");
}
if (thisRowInputs.length == 0)
return true;


完整源代码如下:

var tabTableInput = function (tableId, inputType) {
var rowInputs = [];
var trs = $("#" + tableId).find("tr");
var inputRowIndex = 0;
$.each(trs, function (i, obj) {
if ($(obj).find("th").length > 0) { //跳过表头
return true;
}
var rowArray = [];
var thisRowInputs;
if (!inputType) { //所有的input
thisRowInputs = $(obj).find("input:not(:disabled):not(:hidden):not([readonly])");
} else {
thisRowInputs = $(obj).find("input:not(:disabled):not(:hidden):not([readonly])[type=" + inputType + "]");
}
if (thisRowInputs.length == 0)
return true;

thisRowInputs.each(function (j) {
$(this).attr("_r_", inputRowIndex).attr("_c_", j);
rowArray.push({ "c": j, "input": this });

$(this).keydown(function (evt) {
var r = $(this).attr("_r_");
var c = $(this).attr("_c_");

var tRow
if (evt.which == 38) { //上
if (r == 0)
return;

r--; //向上一行

tRow = rowInputs[r];
if (c > tRow.length - 1) {
c = tRow.length - 1;
}
} else if (evt.which == 40) { //下
if (r == rowInputs.length - 1) { //已经是最后一行
return;
}

r++;
tRow = rowInputs[r];
if (c > tRow.length - 1) {
c = tRow.length - 1;
}
} else if (evt.which == 37) { //左
if (r == 0 && c == 0) {  //第一行第一个,则不执行操作
return;
}
if (c == 0) { //某行的第一个,则要跳到上一行的最后一个,此处保证了r大于0
r--;
tRow = rowInputs[r];
c = tRow.length - 1;
} else { //否则只需向左走一个
c--;
}
} else if (evt.which == 39) { //右
tRow = rowInputs[r];
if (r == rowInputs.length - 1 && c == tRow.length - 1) { //最后一个不执行操作
return;
}

if (c == tRow.length - 1) { //当前行的最后一个,跳入下一行的第一个
r++;
c = 0;
} else {
c++;
}
}

$(rowInputs[r].data[c].input).focus();
});
});

rowInputs.push({ "length": thisRowInputs.length, "rowindex": inputRowIndex, "data": rowArray });

inputRowIndex++;

});
}


调用很简单:

new tabTableInput("tblGrid","text"); 至于后面那个参数,看下源代码就得了

下面给点演示吧

1 2 dsfdf
// var tabTableInput = function (tableId, inputType) {
var rowInputs = [];
var trs = $("#" + tableId).find("tr");
var inputRowIndex = 0;
$.each(trs, function (i, obj) {
if ($(obj).find("th").length > 0) { //跳过表头
return true;
}
var rowArray = [];
var thisRowInputs;
if (!inputType) { //所有的input
thisRowInputs = $(obj).find("input:not(:disabled):not(:hidden):not([readonly])");
} else {
thisRowInputs = $(obj).find("input:not(:disabled):not(:hidden):not([readonly])[type=" + inputType + "]");
}
if (thisRowInputs.length == 0)
return true;

thisRowInputs.each(function (j) {
$(this).attr("_r_", inputRowIndex).attr("_c_", j);
rowArray.push({ "c": j, "input": this });

$(this).keydown(function (evt) {
var r = $(this).attr("_r_");
var c = $(this).attr("_c_");

var tRow
if (evt.which == 38) { //上
if (r == 0)
return;

r--; //向上一行

tRow = rowInputs[r];
if (c > tRow.length - 1) {
c = tRow.length - 1;
}
} else if (evt.which == 40) { //下
if (r == rowInputs.length - 1) { //已经是最后一行
return;
}

r++;
tRow = rowInputs[r];
if (c > tRow.length - 1) {
c = tRow.length - 1;
}
} else if (evt.which == 37) { //左
if (r == 0 && c == 0) { //第一行第一个,则不执行操作
return;
}
if (c == 0) { //某行的第一个,则要跳到上一行的最后一个,此处保证了r大于0
r--;
tRow = rowInputs[r];
c = tRow.length - 1;
} else { //否则只需向左走一个
c--;
}
} else if (evt.which == 39) { //右
tRow = rowInputs[r];
if (r == rowInputs.length - 1 && c == tRow.length - 1) { //最后一个不执行操作
return;
}

if (c == tRow.length - 1) { //当前行的最后一个,跳入下一行的第一个
r++;
c = 0;
} else {
c++;
}
}

$(rowInputs[r].data[c].input).focus();
});
});

rowInputs.push({ "length": thisRowInputs.length, "rowindex": inputRowIndex, "data": rowArray });

inputRowIndex++;

});
}

new tabTableInput("shutaGrid","text");
// ]]>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: