文章目录
简介
下载
使用
1.设置元素可获取焦点
2.设置焦点的样式
3.指定焦点移到到某一个元素上
4.自定义焦点移动
其它
1.提一下初始化
2.监听焦点状态
简介
tv-focusable 是适用于在 TV 端进行网页开发时管理焦点移动的框架,以最简洁的 Api 让前端网页开发就像 android 开发一样自动管理焦点。
下载
npm i tv-focusable
使用
1.设置元素可获取焦点
跟 android 的很相似了吧~
给非 android 开发的同学普及一下,在进行 android 的 TV 端开发时,系统是会自动给 focusable=true 的元素分发焦点的,例如:
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true" />
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true" />
假设这两个元素是左右排列的,当焦点在前面一个 text1 上时,按遥控器的右键,焦点会自动跑到 text2 上。
现在在网页标签上设置 v-focusable 就相当于 android 上设置了 android:focusable=“true”,当用户按遥控器时,该库会像 android 那样自动把焦点移动到下一个焦点上,无需开发者处理。
2.设置焦点的样式
聚焦的元素会被加上一个 class="focus" (你可以自己定义 className,默认为 focus)
现在你应该知道要做什么了,给 focus 设置个独特的样式就好了。
例如这样:
{{ index }}
...
.focus {
transform: scale(1.1);
border: 2px solid red;
box-shadow: 0 0 20px red;
}
[1.gif](file:///E:/web/blog/1.gif)
好了,这样就设置完了,现在你按方向键时焦点就会自动移动到下一个目标元素上了,很简洁吧~
3.指定焦点移到到某一个元素上
上面的演示中最开始时第一个元素获取了焦点,实际上你在使用时,需要你自己来指定让哪个元素聚焦,这个由用户自己来指定似乎更加合适,你可以用下面的方法来指定焦点移动到某个元素上:
this.$tv.requestFocus(Element);
例如:
...
export default class Example1 extends Vue {
created() {
this.$nextTick(() => {
// @ts-ignore
this.$tv.requestFocus(this.$refs.myDiv)
})
}
}
至于如何获取 Element 就不再展开了,你可以用上面示例中 vue 提供的 $refs 方式,也可以用 xpath 等很多方式:
// 让第2个div 聚焦
this.$tv.requestFocus(this.$tv.getElementByPath('//div[@class="demo"]/div[2]'));
一般 TV 端的页面在刚加载完成时,产品都会要求让某一个元素聚焦的,这时你就用上这条 api 了。
注意: 进入页面时想让某个元素聚焦,要在 nextTick 回调中进行,否则会因页面未加载完全而导致焦点移动并不如你所愿。
4.自定义焦点移动
框架有自己的一套找焦点算法,但有时产品要求你在某个元素上按遥控器右方向键时,让屏幕左下角的某个该死的元素聚焦,那你就要根据产品需求文档来自定义焦点移动了。
可以使用 @up,@right,@down,@left 这几个属性来指定按遥控器对应方向键时调用的方法,然后自己在方法里通过 requestFocus 让目标元素聚焦,如果你在自己的方法里调用了 requestFocus 方法,该库将不再执行默认的焦点移动操作,否则依然帮你执行默认的焦点移动。
示例:
...
down(index: number) {
if (index === 2) { //在第2个div上按下方向键时,焦点直接移动到第30个div上
this.$tv.requestFocus(this.$tv.getElementByPath('//div[@class="wrapper"]/div[30]'));
}
}
[2.gif](file:///E:/web/blog/2.gif)
好啦,到这里应该能满足基本所有的 TV 焦点需求了。
你还在看???
好吧,我猜你可能还有一些别的需求~
其它
1.提一下初始化
// 初始化配置
this.$tv.init({
focusClassName: "on-focus", // 聚焦元素的className (默认focus)
KEYS: {KEY_LEFT: [37, 21], KEY_UP: [38, 19], KEY_RIGHT: [39, 22], KEY_DOWN: [40, 20]}, // 自定义键值
scrollEl:this.$tv.requestFocus(this.$tv.getElementByPath('//div[@class="demo"]')), //局部滚动
initDis: 20, // 直线类型找焦点时,按键方向的交叉轴方向允许的最大找焦点范围,(默认20px)
findFocusType: 1 //找焦点方式 0:直线上 1:最近(默认1)
});
如果你有定制一些参数的需求,可以通过初始化设置一下这些参数,否则无须初始化。
下面是参数的一些说明:
1.自定义焦点 class(focusClassName)
你接手了别的组的项目,他们已经把 focus 这个词作为普通 className 给用了,而且很多地方都用到了,你一定不愿意把他们的代码里的 focus 改成 focus1,focus2 什么的,以使你可以正常使用该库的 focus 这个名字作为焦点样式。
那就通过初始化里的 focusClassName 属性重新定义一下该库的焦点样式名吧。
2.自定义键值(KEYS)
不同厂家的遥控器键值可能不一样,有些并未按照 android 键值来实现,而且产品可能要求同时支持遥控器和键盘操作,这时你就需要指定上下左右方向键值了,例如上面配置的 KEY_LEFT: [37, 21] 就是支持键盘上的左箭头键和遥控器左方向键。
3.局部滚动(scrollEl)
TV 端网页大多是整个页面滚动,滚动条在浏览器窗口上,如果你的滚动内容是在整个页面的局部某一块,需要指定一下滚动容器。
5.gif
4.自定义找焦点方式(findFocusType,initDis)
findFocusType=1,即默认找最近焦点方式,用默认方式时实际上用不到 initDis 参数
3.gif
findFocusType=0,initDis = 49
4.gif
initDis 为何是 49?只要下一个 div 的横向中心线和当前焦点元素的中心线距离大于 initDis 值,就认为它和当前焦点不在同一水平线上,现在 div2 的横向中心线比 div1 高了 50px,所以如果你不想让用户在 div1 上按右方向键时焦点跑到 div2 上,就可以设置找焦点方式为直线模式,并通过 initDis 来控制偏差范围。
2.监听焦点状态
@onFocus:获得焦点
@onBlur:失去焦点
@onFocus="focus(index,$event)" @onBlur="blur(index)">
{{ index }}
...
focus(index: number, event: any) {
console.log(event.detail.el); //当前元素
console.log('focus:' + index);
}
blur(index: number) {
console.log('blur:' + index);
}
不需要获取当前元素就不用传 $event 了。