Web页面在电视上的焦点导航
设置元素的tabindex属性值为-1
<div tabindex=-1 class="item" id="nav_item1" >首页</div>
tabIndex属性可以设置键盘中的TAB键在页面元素中的移动顺序,即焦点的顺序。默认情况下,普通元素无法获取焦点,只有链接、表单等元素可以获取焦点。所以普通元素需要设置tabindex属性,再使用foucs()方法即可。当tabindex的值 >= 0时,可以通过Tab键获取焦点,而tabindex = -1时Tab键不能获取焦点,只能通过JS获取。当tabindex的值不为-1的时候,使用遥控器操作时焦点获取位置不符合预期。
设置焦点
完成上诉步骤后,通过调用focus()方法给目标元素设置焦点。如:
view.focus();
Android端有一个默认的导航规则,开发者设置好属性之后通过遥控器导航。在操作遥控器后,它会使当前元素的目标方向上的最近元素获取焦点。web页面默认没有,我们需要建立一个类似的规则。对当前获得焦点元素使用遥控器操作(上、下、左、右键),使当前元素在上、下、左、右方向对应的元素获得焦点。
当前焦点元素
通过document.activeElement可以得到当前界面正获得焦点的元素,十分重要,在建立导航规则后,我们需要通过该元素得到它在各个方向上对应的元素。
建立导航规则
1.创建数组 首先需要对页面中需要获得焦点的元素设置id,然后使用js创建一个二维数组。如下:
var eleArray = [
["nav_item1","nav_item2","nav_item3","nav_item4","nav_item5",""],
["img1", "img1", "img6", "img6", "img6", "img9"],
["img2", "img3", "img6", "img6", "img6", "img9"],
["img4", "img5", "img7", "img7", "img8", "img10"]
];
数组中存入页面元素的id,该二维数组可以反映每一个元素的相对位置,即通过该二维数组我们可以找到每一个元素上下左右方向上对应的元素。
2.获取当前焦点元素在上述数组中对应的位置(行、列)
/**
- 获取对应id在二位数组中的位置
- @param {} id */
function getLocation(id){
var loc = [];
for(var i=0;i<eleArray.length;i++){
for(var j =0;j<eleArray[i].length;j++){
if(eleArray[i][j] == id){
loc[0]=i;
loc[1]=j;
return loc;
}
}
}
}
3.获取当前焦点元素在各个方向上的元素id
获取当前焦点元素上面的元素
getNextTopEle: function(id){
var arr = getLocation(id);
if(arr[0] == 0){
return "";
}else{
var i = arr[0]-1; //上一行
var j = arr[1];
return eleArray[i][j];
}
}
获取当前焦点元素左边的元素
getNextLeftEle: function(id){
var arr = getLocation(id);
if(arr[1] == 0){
return "";
}else{
var i = arr[0];
var j = arr[1]-1; //前一列
return eleArray[i][j];
}
}
获取当前焦点元素下面的元素
getNextBottomEle: function(id){
var arr = getLocation(id);
if(arr[0] == (eleArray.length-1)){
return "";
}else{
var num = arr[0]+1; //从下一行开始遍历,发现是自己继续,直到最后一行或发现其他元素
for(var b = num;b < eleArray.length;b++){
if(eleArray[b][arr[1]] == id){
continue;
}else{
return eleArray[b][arr[1]];
}
}
}
}
获取当前焦点元素右面的元素
getNextRightEle: function(id){
var arr = getLocation(id);
if(arr[1] == (eleArray[0].length-1)){
return "";
}else{
var num = arr[1]+1;//从下一列开始遍历,发现是自己继续,直到最后一列或发现其他元素
for(var b = num;b <eleArray[0].length;b++){
if(eleArray[arr[0]][b] == id){
continue;
}else{
return eleArray[arr[0]][b];
}
}
}
}
4.监听事件并获取焦点
window.addEventListener("keydown",function(){
switch(event.keyCode){
case 37://左
view = document.getElementById(getNextLeftEle(document.activeElement.id));
if(view){
view.focus();
}
break;
case 38://上
view = document.getElementById(getNextTopEle(document.activeElement.id));
if(view){
view.focus();
}
break;
case 39://右
view = document.getElementById(getNextRightEle(document.activeElement.id));
if(view){
view.focus();
}
break;
case 40://下
view = document.getElementById(getNextBottomEle(document.activeElement.id));
if(view){
view.focus();
}
break;
}
})
完成以上步骤,可初步进行焦点导航。
5.特殊操作 通常在开发过程中我们会指定特殊的焦点运动轨迹,从某个元素到指定的一个元素。如下:
var specialArray = [
{id:"img9",nav:"top",target:"nav_item1"}, //当前元素、操作方向、目标元素
{id:"nav_item3",nav:"bottom",target:"img1"}
];
在获取某方向的元素时先遍历specialArray,若发现有该元素以及该方向的操作时,直接返回目标元素。如下:
getNextTopEle: function(id){
var res = "";
for(var i=0;i<specialArray.length;i++){
if(specialArray[i].id == id && specialArray[i].nav == nav){
res = specialArray[i].target;
break;
}
}
//若发现存在特殊操作,直接返回并结束函数
if(res!=null && res!=""){
return res;
}
var arr = getLocation(id);
if(arr[0] == 0){
return "";
}else{
var i = arr[0]-1;
var j = arr[1];
return eleArray[i][j];
}
}
具体见Demo:https://github.com/fengfancky/WebEPG 功能代码都封装在FocusUtils.js中,使用如下:
<script type="text/javascript" src="../js/FocusUtils.js"></script>
...
var eleArray = [
["nav_item1","nav_item2","nav_item3","nav_item4","nav_item5",""],
["img1", "img1", "img6", "img6", "img6", "img9"],
["img2", "img3", "img6", "img6", "img6", "img9"],
["img4", "img5", "img7", "img7", "img8", "img10"]
];
var specialArray = [
{id:"img9",nav:"top",target:"nav_item1"},
{id:"nav_item3",nav:"bottom",target:"img1"}
];
FocusUtils.FindElement.initEle(eleArray);//初始化
FocusUtils.FindElement.addSpecialFocusNav(specialArray);//添加特殊操作