使用HTML、JS等相关Web前端技术基于Android机顶盒开发电视EPG页面。由于电视端使用遥控器进行焦点控制,我们需要对焦点导航进行处理,使用户进行便捷 的交互。
在Android开发中有一个默认的导航规则,开发者设置好相关属性之后可以通过遥控器导航。在操作遥控器后,它会使当前元素的目标方向上的最近元素获取焦点。web没有这样的规则,我们需要建立一个类似的规则。对当前获得焦点元素在使用遥控器操作(上、下、左、右键)时,使当前元素在上、下、左、右方向对应的元素获得焦点。
准备
1.设置元素的tabindex属性值为-1
<div tabindex=-1 class="item" id="nav_item1" >首页</div>
tabIndex属性可以设置键盘中的TAB键在页面元素中的移动顺序,即焦点的顺序。默认情况下,普通元素无法获取焦点,只有链接、表单等元素可以获取焦点。所以普通元素需要设置tabindex属性,再使用foucs()方法即可。当tabindex的值 >= 0时,可以通过Tab键获取焦点,而tabindex = -1时Tab键不能获取焦点,只能通过JS获取。当tabindex的值不为-1的时候,使用遥控器操作时焦点获取位置不符合预期。
注:给元素添加样式 outline: none; 用于去除默认样式。
给需要获取焦点的元素都添加一个相同的类名,如 class="item",将需要获取焦点的元素都筛选出来。
2.获取焦点
完成上诉步骤后,通过调用focus()方法给目标元素设置焦点。如:
view.focus();
3.获取当前焦点元素
通过 document.activeElement 可以得到当前界面正获得焦点的元素,十分重要,在建立导航规则后,我们需要通过该元素得到它在各个方向上对应的元素。
建立导航规则
我们需要建立这样一个规则:当用户按左键时,由当前焦点元素的左边(合适)元素获取焦点。同理,按上、右、下键时,都有对应方向上合适的元素获得焦点。
原理:首先获取当前焦点元素的位置,在与页面中所有元素的位置进行比较,获取各个方向上最合适的元素。
1.获取所有需要获取焦点的元素集合
var className = ".item";//默认值
var list = document.querySelectorAll(className);
可通过下面方法设置或修改,需和html中的class保持一致
setClassName:function(name){
if(name !=null & name != ""){
className = name;
}
}
2.获取元素在页面中的位置
/**
* 获取当前焦点元素在页面中的绝对位置
* @param {当前获取的焦点的元素} e
*/
function getPosition(e){
var x=0,y=0;
while(e!=null){
x += e.offsetLeft;
y += e.offsetTop;
e = e.offsetParent;
}
return {x:x,y:y};
}
3.遍历焦点元素集合找出当前焦点元素在目标方向上最合适的元素
以左方向为例
/**
* 寻找所需方向上最近或最合适的元素
* @param {按键方向} direction
* @param {所有需要获取焦点元素的集合} list
*/
function findFocusId(direction,list){
var currentEle = document.activeElement; //当前焦点元素
var currentLoc = getPosition(currentEle); //当前焦点元素位置
var locele = null;
var minDistance = 99999999;
switch(direction){
case "left":
for(var i=0;i<list.length;i++){ //遍历集合中的所有元素
var loc = getPosition(list[i]); //获取每个元素的位置
if(currentLoc.x >= (loc.x+list[i].offsetWidth)){ //目标元素必须在当前元素的左边
//计算当前元素的左上角到目标元素右上角的距离
var d1 = Math.sqrt(Math.pow(Math.abs(currentLoc.x-loc.x-list[i].offsetWidth),2) +Math.pow(Math.abs(currentLoc.y-loc.y),2));
//计算当前元素的左下角到目标元素的右下角的距离平方
var d2 = Math.sqrt(Math.pow(Math.abs(currentLoc.x-loc.x-list[i].offsetWidth),2) +Math.pow(Math.abs(currentLoc.y+currentEle.offsetHeight-loc.y-list[i].offsetHeight),2));
//记录最小距离和最小距离元素。
var mind = d1<d2 ? d1 : d2;//取最小值
locele = mind < minDistance ? list[i] : locele ;
minDistance = mind < minDistance ? mind : minDistance;
}
}
break;
}
if(locele != null){
return locele.id;
}else{
return null;
}
}
4.添加特殊导航操作
添加自定义属性:
nextLeftFocusId 当前元素左方向上指定的下一个焦点元素的id
nextUpFocusId 当前元素上方向上指定的下一个焦点元素的id
nextRightFocusId 当前元素右方向上指定的下一个焦点元素的id
nextDownFocusId 当前元素下方向上指定的下一个焦点元素的id
在HTML中这样设置:
<img tabindex=-1 id="img9" class="item" nextUpFocusId="nav_item1" nextRightFocusId="img4" >
当该元素获取焦点时,按上键由id为 "nav_item1" 的元素获取焦点,按右键由id为 "img4" 的元素获取焦点。具体实现如下:
var leftFocus = currentEle.getAttribute("nextLeftFocusId");//在html中指定特殊方向的下一个获取焦点元素的id
if(leftFocus!=null&leftFocus != ""){
return leftFocus;
}
在遍历计算之前提前返回。
case "left":
var leftFocus = currentEle.getAttribute("nextLeftFocusId");//在html中指定特殊方向的下一个获取焦点元素的id
if(leftFocus!=null&leftFocus != ""){
return leftFocus;
}
for(var i=0;i<list.length;i++){
var loc = getPosition(list[i]);
if(currentLoc.x >= (loc.x+list[i].offsetWidth)){
//左上角到右上角
var d1 = Math.sqrt(Math.pow(Math.abs(currentLoc.x-loc.x-list[i].offsetWidth),2) +Math.pow(Math.abs(currentLoc.y-loc.y),2));
//左下角到右下角
var d2 = Math.sqrt(Math.pow(Math.abs(currentLoc.x-loc.x-list[i].offsetWidth),2) +Math.pow(Math.abs(currentLoc.y+currentEle.offsetHeight-loc.y-list[i].offsetHeight),2));
var mind = d1<d2 ? d1 : d2;//取最小值
locele = mind < minDistance ? list[i] : locele ;
minDistance = mind < minDistance ? mind : minDistance;
}
}
break;
设置焦点样式
当元素获取焦点时,我们需要改变它的显示样式,来表示它获取了焦点。
1.使用onfocus和onblur
onfocus :获得焦点
onblur:失去焦点
如:
<div tabindex = "-1" class="item" id="area0_div_0" onfocus="search_focus()" onblur="search_blur()" >
<div class="pic pic01" id="area0_pic0"></div>
<div class="txt" id="area0_txt0">搜索</div>
</div>
再实现search_focus和search_blur两个方法,可以分别处理获得焦点和失去焦点的两种样式。
function search_focus(){
document.getElementById("area0_pic0").style.backgroundImage = "url(../images/portal/serach.png)";
document.getElementById("area0_pic0").style.backgroundRepeat = "no-repeat";
document.getElementById("area0_pic0").style.backgroundPosition = "-1px -3px";
document.getElementById("area0_txt0").style.color = "#fff";
}
function search_blur(){
document.getElementById("area0_pic0").style.backgroundImage = "url(../images/portal/serach_dark.png)";
document.getElementById("area0_pic0").style.backgroundPosition = "0px 0px";
document.getElementById("area0_txt0").style.color = "#778796";
}
2.使用:focus伪类
设置未获取焦点的正常状态样式:
.content .item{
outline: none;//去除默认样式
border: 2px solid transparent;
transition: all .5s ease-out;
-webkit-transition: all .5s ease-out;
}
设置获得焦点后的样式:
.content .item:focus{
z-index: 9;
border-radius: 10px;
box-shadow:white 0px 0px 10px ;
border: 2px solid white;
transition: all .4s ease-out;
-webkit-transition: all .4s;
transform: scale(1.2);
-ms-transform:scale(1.2);
-moz-transform:scale(1.2);
-webkit-transform:scale(1.2);
-o-transform:scale(1.2);
}
网友评论