I am curious how the Opera browser implements its keyboard navigation, where you can do Shift + (↑ , ↓ , ← or →) and you travel along a row or a column.
How would you implement this in JavaScript?
I am curious how the Opera browser implements its keyboard navigation, where you can do Shift + (↑ , ↓ , ← or →) and you travel along a row or a column.
How would you implement this in JavaScript?
这是一个起点:
function getCentrePosition(el) {
var x= el.offsetWidth/2, y= el.offsetHeight/2;
while (el!==null && el.nodeType==1) {
x+= el.offsetLeft;
y+= el.offsetTop;
el= el.offsetParent;
}
return [x, y];
}
function arrowKeyHandler(event) {
if (event===undefined) event= window.event;
if (!event.shiftKey) return true;
// Detect which arrow key is pressed. Make a matrix to rotate each
// case onto the default case for left-pressed.
//
var m;
if (event.keyCode===37) m= [[1,0], [0,1]]; // left
else if (event.keyCode===38) m= [[0,1], [-1,0]]; // up
else if (event.keyCode===39) m= [[-1,0], [0,-1]]; // right
else if (event.keyCode===40) m= [[0,-1], [1,0]]; // down
else return true;
// Find link with shortest distance in left and vertical directions.
// Disregard any links not left of the current link.
//
var pos= getCentrePosition(this);
var bestlink= null, bestdist= null;
for (var i= document.links.length; i-->0;) {
var otherpos= getCentrePosition(document.links[i]);
var dx= (otherpos[0]-pos[0])*m[0][0] + (otherpos[1]-pos[1])*m[0][1];
var dy= (otherpos[0]-pos[0])*m[1][0] + (otherpos[1]-pos[1])*m[1][1];
if (dx>=0) continue;
var dist= Math.abs(dx)+Math.abs(dy)*3; // arbitrary biasing factor
if (bestdist===null || dist<bestdist) {
bestlink= document.links[i];
bestdist= dist;
}
}
// Focus closest link in that direction, if any
//
if (bestlink!==null)
bestlink.focus();
return false;
}
// Add to each link on-page, except on Opera which already does it
//
if (!window.opera)
for (var i= document.links.length; i-->0;)
document.links[i].onkeydown= arrowKeyHandler;
这是一个简单的技巧,它通过查看每个链接的中心点与当前链接的中心点(使用旋转矩阵对方向进行标准化)来猜测一个方向的“最佳”链接。您可以通过在向左移动时查看链接的右边缘、向右移动时查看左边缘等等来改进这一点。并且可能它应该编译页面上所有可聚焦元素的列表(包括表单字段和带有 tabindex 的元素),而不仅仅是链接。
您还可以调用诸如 document.moveFocusUp() 和 document.moveFocusDown() 之类的函数 .. 但我猜这有点作弊,而且它只能在 Opera 中工作;)
(这些方法与“空间导航”的内置逻辑挂钩,即将焦点移动到链接或按钮 Opera 认为在给定方向上的最佳匹配)
这可以在 CSS 中快速轻松地完成。在这里阅读:
https://dev.opera.com/tv/tweaking-spatial-navigation-for-tv-browsing/
<a id="1" href="#" style="nav-up: #3; nav-right: #2;">Link 1</a>
<a id="2" href="#">Link 2</a>
<a id="3" href="#">Link 3</a>
在此示例中,如果焦点打开Link 1
并且用户Shift
按住并按下Right
,焦点将跳转到Link 2
。如果用户Shift
按住并按下,无论链接在页面上的什么位置,Up
焦点都会跳转到。Link 3