欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

电视EPG(WEB)页面上的焦点导航方案

程序员文章站 2022-05-14 22:20:35
...

使用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);
}

DEMO

见:https://github.com/fengfancky/WebEPG