文章目录

  • 简介
  • 安装
  • 如何使用
    • 设置元素可获取焦点
    • 设置焦点的样式
    • 获取 focusable 的引用
    • 指定焦点移到到某一个元素上
      • XPath 获取 DOM—getElementByPath(string)
      • 根据 DOM 反向获取 XPath 路径 —readXPath(el)
    • 自定义焦点移动
    • 表单控件,按确定键进行填写
  • 其它
    • 初始化
      • 自定义焦点 class(focusClassName)
      • 自定义键值(KEYS-配置上下左右,enter键值)
      • 自定义找焦点方式(findFocusType,initDis)
      • 边缘距离(offsetDistance)
    • 局部滚动(setScrollEl/resetScrollEl)
    • 自定义事件
      • 监听焦点状态
      • 点击
      • 长按
      • 方向按键
    • 设置属性/重置属性
    • 其它可能用到的方法
    • 所有可配置项
      • 属性
      • 方法
      • 事件
  • 案例源码请戳这里

简介

tv-focusable 是适用于在 TV 端进行网页开发时管理焦点移动的框架,以简洁的 Api 让前端网页开发就像 android 开发一样自动管理焦点。

更多案例展示
react-tv-focusable
ng-tv-focusable

安装

npm i vue-tv-focusable

如何使用

vue2.x main.js中添加如下代码

import Vue from "vue";
import App from "./App.vue";// 添加下面两行
import focusable from 'vue-tv-focusable';
Vue.use(focusable);Vue.config.productionTip = false;
new Vue({render: h => h(App)
}).$mount("#app");

vue3.x

// main.js中添加如下代码
import { createApp } from 'vue'
import App from './App.vue'import focusable from 'vue-tv-focusable'
createApp(App).use(focusable).mount('#app')

设置元素可获取焦点

<div v-focusable>可获取焦点的元素</div>
<div>不可获取焦点的元素</div>// 1.1.0版本增加
<div v-focusable="true">可获取焦点的元素</div>
<div v-focusable="false">不可获取焦点的元素</div>

跟 android 很相似了吧~
给非 android 开发的同学普及一下,在进行 android 的 TV 端开发时,系统是会自动给 focusable=true 的元素分发焦点的,例如:

    <TextViewandroid:id="@+id/text1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:focusable="true" /><TextViewandroid: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 那样自动把焦点移动到下一个焦点上,无需开发者处理。
别急,现在还看不到焦点效果,因为你还没设置聚焦的样式呢。

设置焦点的样式

聚焦的元素会被加上一个 class="focus" (你可以自己定义 className,默认为 focus),现在你应该知道要做什么了,给 focus 设置个独特的样式就好了。
例如这样:

<div class="demo"><div class="item" v-focusable v-for="index in 10" :key="index">{{ index }}</div>
</div>
...
.focus {transform: scale(1.1);border: 2px solid red;box-shadow: 0 0 20px red;
}


好了,这样就设置完了,现在你按方向键时焦点就会自动移动到下一个目标元素上了,很简洁吧~

获取 focusable 的引用

vue2.x 获取方式

// 方式一:导入
import { focusable } import 'vue-tv-focusable'
focusable.xxx// 方式二:在vue上下文中可直接获取 $tv
this.$tv.xxx

vue3.x 获取方式

// 导入
import { focusable } import 'vue-tv-focusable'//方式二:在setup()中获取$tv对象
import { getCurrentInstance } from 'vue'
setup() {const { proxy, ctx } = getCurrentInstance(); proxy.$tv.xxx...
}

指定焦点移到到某一个元素上

上面的演示中,最开始时第一个元素获取了焦点,实际上你在使用时,库并不会在页面渲染完成后主动帮你聚焦到第一个或某个元素上,这个由你自己来指定似乎更加合适,你可以用下面的方法来指定焦点移动到某个元素上:

this.$tv.requestFocus(Element,bool); // Element 必填; bool 非必填,默认为true

关于第二个参数,设置聚焦时是否需要滚动动画,默认 true 带动画,如果指定的聚焦元素不在窗口可视区域内或未完全显示,聚焦后就会被滚动到可视区域内,有些场景下你可能并不想要动画,例如类似 “回到顶部” 的场景,就需要用到这个了,试一下看看吧~
例如:

<div class="item" ref="myDiv">s</div>
...
export default class Example1 extends Vue {created() {this.$nextTick(() => {// @ts-ignorethis.$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 回调中进行,否则会因页面未加载完全而导致焦点移动并不如你所愿。

XPath 获取 DOM—getElementByPath(string)

vue-tv-focusable 提供了 xPath 的方式获取

<body><div class="content"><span class="item1">1</span><span class="item2">2</span><span class="item3">3</span></div>
</body>
this.$tv.getElementByPath('//div[@class="content"]/span[2]');
this.$tv.getElementByPath(this.$tv.readXPath(document.querySelector('.item2')));
//结果: <span class="item2">2</span>
根据 DOM 反向获取 XPath 路径 —readXPath(el)

vue-tv-focusable 根据 DOM 反向获取 XPath 路径

<body><div class="content"><span class="item1">1</span><span class="item2">2</span><span class="item3">3</span></div>
</body>
this.$tv.readXPath(document.querySelector('.item2'))
this.$tv.readXPath(this.$tv.getElementByPath('//div[@class="content"]/span[2]');)
//结果: "/html/body/div[1]/span[2]"

自定义焦点移动

框架有自己的一套找焦点算法,但有时产品会要求你在某个元素上按遥控器右方向键时让屏幕左下角的某个该死的元素聚焦,那你就要根据产品需求文档来自定义焦点移动了。
可以使用 @up,@right,@down,@left 这几个属性来指定按遥控器对应方向键时调用的方法,然后自己在方法里通过 next 或 requestFocus(1.x只支持此方法) 让目标元素聚焦;

1.x写法
如果你在自己的方法里调用了 requestFocus 方法,该库将不再执行默认的焦点移动操作,否则依然帮你执行默认的焦点移动。
示例:

<div class="wrapper"><div class="focus-item" v-focusable v-for="index in 1000" :key="index" @down="down(index)">
</div>
...down(index: number) {if (index === 2) { //在第2个div上按下方向键时,焦点直接移动到第30个div上this.$tv.requestFocus(this.$tv.getElementByPath('//div[@class="wrapper"]/div[30]'));}}

2.x写法
只要你在标签上定义了方向键监听例如@left,那么在此标签上按左键时该库将不会再执行默认的向左焦点移动操作,你可以通过如下用法来移动焦点:

<div class="wrapper"><div class="focus-item" v-focusable v-for="index in 1000" :key="index" @left="left(index)">
</div>
...left(index: number) {if (index === 2) { //和requestFocus功能是一样的,推荐使用nextthis.$tv.next(this.$tv.getElementByPath('//div[@class="wrapper"]/div[30]'))//或者如果你想在处理一些事情之后再执行库的默认移动setTimeout(() => {this.$tv.next("left")}, 500);}}


推荐使用 2.x 的监听,可同时支持同步和异步流程,1.x只支持同步流程。

表单控件,按确定键进行填写

// formAutofocus:默认truethis.$tv.formAutofocus=false;// 不可以输入this.$tv.formAutofocus=true;// 可以输入

好啦,到这里应该能满足基本所有的 TV 焦点需求了。

你还在看???
好吧,或许你还有一些别的需求~

其它

初始化

可以在全局或某个页面上配置属性

// 初始化配置
// 全局配置可在mian.js中,也可以放在APP.vue中
const vm = new Vue();
// 1.使用init同时配置多个属性
vm.$tv.init({focusClassName: "on-focus", // 聚焦元素的className (默认focus)KEYS: {KEY_LEFT: [37, 21], KEY_UP: [38, 19], KEY_RIGHT: [39, 22], KEY_DOWN: [40, 20],KEY_ENTER: [13, 23]}, // 自定义键值longPressTime: 800, // 长按响应时间(单位:毫秒),默认500msdistanceToCenter: false // 使焦点始终在可视范围的中间部分,默认false
});// 2.单独设置某个属性
vm.$tv.KEYS=  {KEY_LEFT: [37, 21], KEY_UP: [38, 19], KEY_RIGHT: [39, 22], KEY_DOWN: [40, 20],KEY_ENTER: [40, 20]
};
vm.$tv.longPressTime= 800;

**警告:**为了不影响通用配置,如果对某页面进行了一些特殊配置,请记住在销毁页面时重置它

created(){this.$tv.findFocusType  = 0;
}
destroyed() {this.$tv.resetFindFocusType(); //this.$tv.findFocusType  = 1;
}

上面列举了几个常用且一般设置成整个项目所有页面通用的属性,可在文档最下方查看所有可配置属性,如果不需要定制属性,无须初始化。
通常情况下,默认属性就能满足大部分项目的需求。

下面是几个常用参数使用场景的举例说明:

自定义焦点 class(focusClassName)

你接手了别的组的项目,他们已经把 focus 这个词作为普通 className 给用了,而且很多地方都用到了,你一定不愿意把他们的代码里的 focus 改成 focus1,focus2 什么的,以使你可以正常使用该库的 focus 这个名字作为焦点样式。
那就通过初始化里的 focusClassName 属性重新定义一下该库的焦点样式名吧。

自定义键值(KEYS-配置上下左右,enter键值)

不同厂家的遥控器键值可能不一样,有些并未按照 android 键值来实现,而且产品可能要求同时支持遥控器和键盘操作,这时你就需要指定上下左右方向键值了,例如上面配置的 KEY_LEFT: [37, 21] 就是支持键盘上的左箭头键和遥控器左方向键。

自定义找焦点方式(findFocusType,initDis)

findFocusType=1,即默认找最近焦点方式,用默认方式时实际上用不到 initDis 参数

findFocusType=0,initDis = 49

initDis 为何是 49?只要下一个 div 的横向中心线和当前焦点元素的中心线距离大于 initDis 值,就认为它和当前焦点不在同一水平线上,现在 div2 的横向中心线比 div1 高了 50px,所以如果你不想让用户在 div1 上按右方向键时焦点跑到 div2 上,就可以设置找焦点方式为直线模式,并通过 initDis 来控制偏差范围。

边缘距离(offsetDistance)

到达边缘的时候,给焦点和边缘一个距离.
当某个未完全显示在窗口可视区域内的元素聚焦时,该库会自动帮你将这个元素滚动到窗口内完全显示,不过默认状态是贴着边缘的,如果你想让它离这个边缘有一个距离,就可以通过这个属性实现了。

this.$tv.offsetDistance = 50 // 完全显示出来后再距离边缘50像素

如图:

局部滚动(setScrollEl/resetScrollEl)

TV 端网页大多是整个页面滚动,滚动条在浏览器窗口上,如果你的滚动内容是在整个页面的局部某一块,需要指定滚动容器。
setScrollEl(Element): 设置滚动的el
resetScrollEl(): 重置el,即滚动浏览器的滚动条
举个例子:

<div class="demo"><div class="wrapper"><div class="focus-item" v-focusable v-for="index in 300" :key="index">{{ index }}</div></div>
</div>
<script>...created() {this.$nextTick(() => {this.$tv.scrollEl = this.$tv.getElementByPath('//div[@class="demo"]')//this.$tv.setScrollEl(this.$tv.getElementByPath('//div[@class="demo"]'));})}destroyed() {// To avoid affecting the global configuration, reset the page when destroying itthis.$tv.resetScrollEl();}...
</script>
<style>.demo {background:#ccc; margin: 0 auto; width: 400px; height: 400px; position: relative; padding: 20px; overflow: hidden;.wrapper { width: 800px; }.focus-item {...}}
</style>

自定义事件

监听焦点状态

@onFocus:获得焦点
@onBlur:失去焦点

<div class="focus-item" v-focusable v-for="index in 300" :key="index" @down="down(index)"@onFocus="focus(index,$event)" @onBlur="blur(index)">{{ index }}
</div>
...
focus(index: number, event: any) {console.log(event.detail.el); //当前元素console.log('focus:' + index);
}blur(index: number) {console.log('blur:' + index);
}

不需要获取当前元素就不用传 $event 了。

点击

@click
按遥控器 OK 键(相当于手机上手指点击按钮,PC 上鼠标点击按钮)

<div class="focus-item" v-focusable @click="click">button</div>
...
click() {console.log('click');
}

Tip: 如果上例中的 div 是一个 component,需要写成 @click.native

长按

@longPress
按下遥控器 OK 键超过 500ms 会触发长按事件,可通过 $tv.longPressTime 自定义这个时间

<div class="focus-item" v-focusable @longPress="longPress">11</div>
...
longPress() {console.log('longPress');
}
方向按键

@left,@right,@up,@down
TV 端依靠遥控器按上下左右方向键来操作界面,可自定义方向事件监听,例如监听右键按键事件

<div class="focus-item" v-focusable @right="right">11</div>
...
right() {console.log('right');
}

设置属性/重置属性

// 重置成插件默认值,reset+属性名(),例如
this.$tv.resetScrollEl();
this.$tv.resetFocusClassName();//清除所有配置并恢复到插件的默认配置
this.$tv.reset()
...// 独立配置init里面的每一项,$tv.属性名=xx, 如下:
this.$tv.focusClassName = XX;
this.$tv.offsetDistance = XX;
...

其它可能用到的方法

元素聚焦状态的全局监听- setOnFocusChangeListener

this.$tv.setOnFocusChangeListener((element, focus)=>{console.log("焦点状态改变的元素:" + element, "聚焦或失去焦点:" + focus)
})

让页面滚动到某个元素的位置

this.$tv.scrollTo({targetEl: document.querySelector("#page1")})

参数说明:
scrollEl:滚动区域,默认为 document,
targetEl:需要滚动到哪个元素,
isCenter:targetEl 是否滚动到屏幕居中的位置,
offset:距离滚动边界上下左右的偏移,
smooth:是否开启滚动动画,
duration:动画耗时,默认200毫秒

所有可配置项

属性
name 描述 默认值
itemAttrname 可聚焦的属性名
this.$tv.itemAttrname= “myFocusable”;
focusable
focusClassName 指定焦点元素类名
this.$tv.focusClassName = “myFocus”;
focus
findFocusType 移动类型,1:就近查找 0:直线查找
this.$tv.findFocusType = 1;
1
initDis 差值
this.$tv.initDis = 20;
20
KEYS 上下左右的键值
this.$tv.KEYS = {…};
{ KEY_LEFT: [37, 21], KEY_UP: [38, 19], KEY_RIGHT: [39, 22], KEY_DOWN: [40, 20], KEY_ENTER:[13, 23] }
offsetDistance 边缘距离(单位px)
this.$tv.offsetDistance = 50;
50
longPressTime 长按响应时间(单位毫秒)
this.$tv.longPressTime = 500;
500
scrollEl 设置可以滚动的el
this.$tv.scrollEl = ;
null
limitingEl 整个界面,只有limitingEl内的焦点可以聚焦
this.$tv.limitingEl = ;
null
distanceToCenter 焦点是否在滚动区域保持居中显示
this.$tv.distanceToCenter = true;
false
formAutofocus 表单控件是否可以输入或者编辑
$tv.formAutofocus= false;
true
smoothTime 滚动的动画时间
$tv.smoothTime= 200;
200
spacingTime 滚动的动画帧数(数值越小,滚动动画帧数越多,动画更细腻,也会更耗性能)
$tv.spacingTime = 20;
20
scrollSpeedX 控制水平方向按键速度(单位毫秒),例如200ms内只执行一次按键事件
$tv.scrollSpeedX = 200;
0
scrollSpeedY 控制垂直方向按键速度(单位毫秒)
$tv.scrollSpeedY = 200;
0
scrollSpeed 控制水平和垂直方向按键速度(单位毫秒)
$tv.scrollSpeed = 200;
0
方法
name 描述 参数类型
next(el|str) 执行聚焦操作,可传期望的目标元素或方向标识 Element 或 string
requestFocus(el) 执行聚焦操作,已在2.x被next取代 Element
getElementByPath(str) 使用xPath获取element string
readXPath(el) 根据DOM反向获取XPath路径 Element
resetScrollEl() 重置成浏览器滚动
resetFocusClassName() 重置 focusClassName
resetInitDis() 重置 initDis
resetFindFocusType() 重置 findFocusType
resetKEYS() 重置 KEYS
resetOffsetDistance() 重置 offsetDistance
resetLongPressTime() 重置 longPressTime
resetDistanceToCenter() 重置 distanceToCenter
resetScrollEl() 重置 scrollEl
resetLimitingEl() 重置 limitingEl
resetFormAutofocus() 重置 formAutofocus
reset() 重置所有配置
事件
name 描述
up 上移 (可配置KEY_UP修改键值)
right 右移 (可配置KEY_RIGHT修改键值)
down 下移 (可配置KEY_DOWN修改键值)
left 左移 (可配置KEY_LEFT修改键值)
onFocus 获取焦点
onBlur 失去焦点
longPress 长按 (可配置KEY_ENTER修改键值), $tv.init.longPressTime可配置长按的时间,默认500ms
click 按enter时可触发click(可配置KEY_ENTER修改键值)

案例源码请戳这里

vue-tv-focusable相关推荐

  1. vue开发android tv,vue-tv-focusable中文文档

    文章目录 简介 下载 使用 1.设置元素可获取焦点 2.设置焦点的样式 3.指定焦点移到到某一个元素上 4.自定义焦点移动 其它 1.提一下初始化 2.监听焦点状态 简介 tv-focusable 是 ...

  2. vue多张图片实现TV端长图浏览组件

    vue多张图片实现长图组件 上一篇写了vue中如何实现长图效果,实现的是单张图片,本文讲解多张图片实现长图,直接上代码: 1.布局代码如下: <template><div class ...

  3. vue开发android tv,h5做APP TV(电视端APP vue框架)-Go语言中文社区

    先px转rem,然后把psd上传蓝湖,把尺寸改为750的图纸,按照上面的尺寸来写代码 1.安装px2rem-loader npm install px2rem-loader 2.配置px2rem-lo ...

  4. h5做APP TV(电视端APP vue框架)

    先px转rem,然后把psd上传蓝湖,把尺寸改为750的图纸,按照上面的尺寸来写代码 1.安装px2rem-loader npm install px2rem-loader 2.配置px2rem-lo ...

  5. 【Android TV 开发】焦点处理 ( 父容器与子组件焦点获取关系处理 | 不同电视设备上的兼容问题 | 触摸获取焦点 | 按键获取焦点 )

    Android TV 开发系列文章目录 [Android TV 开发]安卓电视调试 ( 开启网络远程调试 ) [Android TV 开发]焦点处理 ( 父容器与子组件焦点获取关系处理 | 不同电视设 ...

  6. SpringBoot+Vue实现请求后台获取Base64编码的图片验证码并使用Redis缓存实现2分钟内有效

    场景 前端Vue的登录页面,验证码请求后台,后台生成验证码照片后使用Base64编码后, 返回给前端,前端进行显示. 注: 博客: https://blog.csdn.net/badao_liuman ...

  7. TypeScript+vue使用与迁移经验总结

    源宝导读:ERP平台的前端底层使用了Vue作为组件的基础架构,而使用了TypeScript语言进行组件的封装与开发.本文将简要介绍平台在使用TypeScript和Vue框架进行老功能重构时的经验总结. ...

  8. Nginx 部署 Vue 项目刷新页面出现404

    问题 使用Vue.框架,利用vue-route编写了一个单页路由项目,运维协助在服务器端配置nginx.部署完成后,访问首页没问题,从首页里打开二级页面没问题,但是所有的二级页面打开后,再次刷新,就会 ...

  9. vue 限制渲染条数_深入理解Vue 的条件渲染和列表渲染

    这两天学习了Vue.js 感觉条件渲染和列表渲染知识点挺多的,而且很重要,所以,今天添加一点小笔记. 条件渲染 v-if 在 < template > 中配合 v-if 渲染一整组 在使用 ...

  10. GridView xml中设置android:focusable=false无效的原因

    最近Tv项目中有个小问题,需要gridview展示内容,但是不可获取焦点,于是xml中设置android:focusable="false",设想会成功,但是实际操作,发现还是可以 ...

最新文章

  1. 文件节点的linux指令,Java工程师必学的Linux命令(一)文件与目录管理
  2. Ubuntu 安装OpenCV3.0.0
  3. 测试Hadoop2.7.1
  4. 改变eclipse工程中代码的层次结构
  5. 最短路径迪杰斯特拉算法 c语言,Dijkstra第K最短路径算法
  6. vue如何split_vue代码分割的实现(codesplit)
  7. java nio 事件_Java NIO原理及实例
  8. resent代码详解
  9. AutoDesk EAGLE 9.6.2 Free版 在win10下闪退的解决方法
  10. LEDE独臂路由器无法上网踩坑
  11. 巧用金山网盾对付游戏插件强行锁定主页
  12. matlab中换行操作
  13. 首次全面深度解密华为方舟编译器
  14. 那些年,Linus torvalds大神喷过的技术
  15. DELPHI 7 LITE v3.0 [SP1.1 Integrated] (安装版含绿色版)(可选D2007RTL)(2008-5-29)
  16. GRPC: 如何优雅关闭进程(graceful shutdown)?
  17. access_token(接口访问凭证)
  18. 投资、投机、赌博、交易
  19. BIOS14: Hypothesis testing(假设检验)using R
  20. 获取谷歌浏览器Chrome缓存目录

热门文章

  1. 韩顺平php从入门到精通讲义,传智播客_韩顺平_php从入门到精通
  2. 罗技g502 g102游戏驱动ghub详细 教程
  3. 基于YACC的TINY语法分析器的构建
  4. 计算机组成白中英答案,计算机组成原理白中英答案
  5. 【CarMaker学习笔记】Simulink内的子模块详细介绍
  6. 火山PC编辑框组件详解2
  7. python下载第三方库失败的解决办法
  8. MPLS OPTION-B
  9. android直播弹幕开发,Android上专为视屏直播打造的轻量级弹幕库(100多kb)
  10. AndroidProject