Skip to content

移动规则 ​

按下方向键时,vuEPG 根据元素在屏幕上的实际位置选出下一个焦点。整个过程可以概括为两句话:

  1. 先在同一层级里挑:同一个分组内,按“方向 → 重叠 → 最近”三步挑出目标;
  2. 挑不到就往外走一层:把整个分组当作一个元素,到外层继续挑。

本页的示意图都由 vuEPG 真实的导航算法实时计算,点击图下方的步骤按钮,可以逐步查看每一步保留和排除了哪些元素。

当前焦点 O候选参与比较目标已排除

同一层级:三步挑选 ​

① 只看这个方向上的元素 ​

按 ↓ 时只考虑位于 O 下方的元素,按 → 时只考虑位于 O 右方的元素,其余全部排除。

ABCDEO

D 距离最近,成为目标。

试一试

点击右下角的方向按钮切换方向。注意斜向的 E:按 ↓ 或 → 时它虽然在这个方向上,但最终没有被选中,原因见下一步。

② 优先同一行 / 同一列 ​

在该方向的元素中,与 O 有重叠的优先:上下移动时看左右方向是否重叠,左右移动时看上下方向是否重叠。图中的阴影带就是 O 的覆盖范围。

XYO

Y 距离最近,成为目标。

X 离 O 更近,但它在斜下方,与 O 没有重叠;Y 虽然更远,但与 O 在同一列,所以选 Y。这符合遥控器的直觉:按 ↓ 应该落在正下方,而不是斜下方。

没有重叠时,只看完全越过的元素 ​

如果该方向上没有任何元素与 O 重叠,就只考虑完全位于 O 那一侧的元素(按 ↓ 时,上边缘要低于 O 的下边缘)。

STUO

T 距离最近,成为目标。

U 与 O 在同一高度,不在下方,第①步就被排除;S 与 O 上下交叠,并不“完全在下方”,第②步被排除;只剩 T。

③ 最后选最近的 ​

在剩下的元素中,选距离最近的:按 ↓ 时比较上边缘,按 ↑ 时比较下边缘,按 ← → 时同理比较左右边缘。

距离相同时,选与 O 更对齐的:上下移动时比较左边缘,左右移动时比较上边缘。逐层向外查找时,如果距离并列,先比较候选与当前焦点元素在交叉轴上的间距,再比较与整组的对齐程度。仍然相同时,选文档中靠前的。

LRO

L、R 距离相同,取与 O 更对齐的 R。

L 和 R 的上边缘在同一高度,距离相同;R 几乎正对着 O,更对齐,所以选 R。

边缘相接不算重叠 ​

判断重叠时,O 两侧各向内收缩 5%,避免只是边缘碰到一点的元素被当作“同一列”。

PQO

Q 距离最近,成为目标。

P 与 O 只重叠了 3 像素,没有超过收缩范围,不算重叠;Q 在阴影带内,所以选 Q。

跨层级:逐层向外 ​

在分组内挑不到目标时,vuEPG 会先在这个分组上派发可取消的方向事件,再把整个分组当作一个元素,在外一层继续按上面的三步挑选。挑中的如果是一个分组,就进入这个分组。

点击图中的项目,观察焦点与事件分组 A分组 B · B2 为默认入口A1A2A3B1B2B3B4
分组 A
分组 B
点击后用方向键操作
  1. 事件日志

试试下面几种操作,对照右侧的事件日志:

操作过程结果
焦点在 A1,按 →分组 A 内右侧没有元素 → 以整个分组 A 为起点 → 右侧找到分组 B → 进入分组 BB2
焦点在 B1,按 ←分组 B 内左侧没有元素 → 以整个分组 B 为起点 → 左侧找到分组 A → 进入分组 AA1
焦点在 A1,按 ↑分组 A 内上方没有元素 → 外层也没有 → 保持不动A1
焦点在 B2,按 ↓分组 B 内下方最近的是 B4B4

注意第一行:从 A1 按 → 落在 B2 而不是几何上更近的 B1,因为 B2 是分组 B 的默认焦点(★)。

进入分组时落在哪里 ​

按以下顺序查找第一个可以获得焦点的元素:

  1. 带 default 的子节点;
  2. 其余子节点,按文档顺序;
  3. 子节点是分组时,递归进入该分组,规则相同。

哪些元素会被跳过 ​

节点可以成为目标的条件
EPGItem未禁用,且已渲染(自身和祖先都不是 display: none,且在文档中)
EPGGroup未禁用、已渲染,且组内至少有一个可以获得焦点的元素

visibility: hidden 与 position: fixed 的元素视为已渲染。

没有焦点或焦点失效时 ​

页面还没有焦点时,第一次方向操作会落在页面入口,也就是对整个页面套用“进入分组”的规则。

焦点元素被卸载或隐藏(例如切换了 KeepAlive 页面)后,下一次方向操作优先进入原焦点路径中最内层仍可进入的分组;这些分组都不可进入时才回到页面入口。已获得焦点的元素后来被禁用,只影响它能否成为下一次移动的目标;它仍可作为移动的起点。

源码 ​

规则与源码逐条对应,并由单元测试覆盖:

基于 MIT 许可发布 · 支持项目