使用方向键在输入框矩阵中自然的导航

博客介绍了Web页输入框使用键盘导航的相关内容。核心技术有两个,一是用TextRange获取输入框光标位置,便于用户在输入框切换时用上下左右键移动光标;二是为TABLE对象创建映射表,以解决查找当前输入框的切换目标输入框问题。

    关于使用键盘来在Web页的输入框中导航这个事我一周前就说了,今天才把它整理完,真是不好意思。不过整理后的代码结构清晰、使用方便、价格公道、童叟无欺。
    主要的核心技术就是两个,一个是:使用TextRange获取输入框中光标的位置,另一个是:为Web页中的TABLE对象创建一个映射表。其中获取输入框中的光标位置,是为了使用户在输入框间切换时,还能在同一个输入框中继续使用上下左右键移动光标,否这一但使用方向键就切换回很难与使用的。建立Table的映射表是为了解决查找当前输入框的切换目标输入框。
    由于昨天介绍了Mapping的方法,所以获取sibling的输入框就变的非常的简单,代码为:

ExpandedBlockStart.gif ContractedBlock.gif < script  language ="javascript" > dot.gif
InBlock.gifKeyNavigation.GetSiblingCell 
= function(tbl, cell, dir)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gif    KeyNavigation.CreateTableMapping(tbl);
InBlock.gif    
var colIndex = -1;
InBlock.gif    
var row = cell.parentElement;
InBlock.gif    
var rowIndex = row.rowIndex; 
InBlock.gif    
for ( var i=0 ; i < tbl.columnCount ; ++i )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif         
if ( tbl.tableMap[rowIndex][i] == cell )
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif{
InBlock.gif             colIndex 
= i;
InBlock.gif             
break;
ExpandedSubBlockEnd.gif         }
 
ExpandedSubBlockEnd.gif    }

InBlock.gif    
if ( colIndex == -1 )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif         
throw "can't find the cell in table.";
ExpandedSubBlockEnd.gif    }

InBlock.gif    
var siblingCell = null
InBlock.gif    
var incV, incH;
InBlock.gif    incV 
= 1, incH = 1;
InBlock.gif    
switch(dir)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
case KeyNavigation.Up :
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            incV 
= -1;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
case KeyNavigation.Down :
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
for ( var i=1 ; i < tbl.rowCount ; ++i )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                 
var tmpRowIdnex = (tbl.rowCount+rowIndex+i*incV)%tbl.rowCount;
InBlock.gif                 siblingCell 
= tbl.tableMap[tmpRowIdnex][colIndex];
InBlock.gif                 
if ( KeyNavigation.IsAvailableCell(siblingCell) )
ExpandedSubBlockStart.gifContractedSubBlock.gif                 
dot.gif{
InBlock.gif                     
break;   
ExpandedSubBlockEnd.gif                 }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
case KeyNavigation.Left :
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            incH 
= -1;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
case KeyNavigation.Right :
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
for ( var i=1 ; i < tbl.columnCount ; ++i )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                 
var tmpColumnIdnex = (tbl.columnCount+colIndex+i*incH)%tbl.columnCount;
InBlock.gif                 siblingCell 
= tbl.tableMap[rowIndex][tmpColumnIdnex];
InBlock.gif                 
if ( KeyNavigation.IsAvailableCell(siblingCell) )
ExpandedSubBlockStart.gifContractedSubBlock.gif                 
dot.gif{
InBlock.gif                     
break;   
ExpandedSubBlockEnd.gif                 }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
return siblingCell;
ExpandedBlockEnd.gif}
;
None.gif< FONT>
< SPAN>script>

    由于up和down,left和right其实是相同的搜索代码,所以使用一个incV和incH把它们合并成了一段代码。如果在被查询单元格的同列或同行上没有别的输入框,那么siblingCell返回null。
    由于使用了Table的Mapping结果后,键盘的处理反而比查询sibling cell还复杂那么一点点了,处理代码如下:
ExpandedBlockStart.gif ContractedBlock.gif < script  language ="javascript" > dot.gif
InBlock.gifKeyNavigation.DoKeyDown 
= function(elmt)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gif    
var tbl = elmt;
InBlock.gif    
var input = event.srcElement;
InBlock.gif    
var keyCode = event.keyCode;
InBlock.gif    
var iPsn = KeyNavigation.GetCaretPosition(input);
InBlock.gif    
var cell = input.parentElement;
InBlock.gif    
var siblingCell = null;
InBlock.gif    
var directionV = KeyNavigation.Down;
InBlock.gif    
switch(keyCode)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
case 27 : /**//* Escape */
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            KeyNavigation.GetCaretPosition(txb);
InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
case 38 : /**//* Move Up */
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            directionV 
= KeyNavigation.Up;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
case 40 : /**//* Move Down */
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
var isTab = false;
InBlock.gif            
if ( input.tagName == 'TEXTAREA' )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if ( iPsn == KeyNavigation.PreviousCursorPosition || 
InBlock.gif                    ( ( iPsn 
== 0 && directionV == KeyNavigation.Up ) || 
InBlock.gif                    ( iPsn 
== input.value.length && directionV == KeyNavigation.Down ) ) )
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    isTab 
= true;
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    KeyNavigation.PreviousCursorPosition 
= iPsn;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
if ( input.tagName == 'INPUT' || isTab )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                siblingCell 
= KeyNavigation.GetSiblingCell(tbl, cell, directionV);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
case 37 : /**//* Move Left */
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if ( iPsn == 0 )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                 siblingCell 
= KeyNavigation.GetSiblingCell(tbl, cell, KeyNavigation.Left);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
case 39 : /**//* Move Right */
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if ( iPsn == input.value.length )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
InBlock.gif                 siblingCell 
= KeyNavigation.GetSiblingCell(tbl, cell, KeyNavigation.Right);
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
if ( siblingCell && siblingCell != cell )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
var siblingInput = null;
InBlock.gif        
var inputs = siblingCell.all.tags('INPUT');
InBlock.gif        
if ( inputs.length > 0 )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            siblingInput 
= inputs[0];
InBlock.gif            siblingInput.focus();
ExpandedSubBlockEnd.gif        }

InBlock.gif        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            siblingInput 
= siblingCell.all.tags('TEXTAREA')[0];
InBlock.gif            siblingInput.focus();
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}
;
None.gif
< SPAN>script>
    麻烦的地方是,需要区别对待INPUT和TEXTAREA这两个输入框元素。对于INPUT的处理很简单,UP和DOWN直接就执行跳离,LEFT的时候看看光标POSITION是否为0,RIGHT的时候看看是否为input.value.length。而TEXTAREA的LEFT和RIGHT和INPUT的处理是一样的,但是它的UP和DOWN为了让用户用起来比较的自然,加入了一个 KeyNavigation.PreviousCursorPosition,用来记忆上一次的按键时TEXTAREA里的光标位置,当响应UP和DOWN的时候,如果光标不在输入框TEXTAREA的两头(0和input.value.length),那么需要KeyNavigation.PreviousCursorPosition==iPsn才执行跳离操作。
    说了半天不明白,自己试试Navigate的效果就知道了emsmile.gif。    
   
text
text
texttexttext textsdaf
texttext
texttext textsdaftext
text
text
texttext
text
texttext textsdaftext
texttext textsdaf asdfsdfsdf
text

    操作体验还算自然吧 emwink.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值