为键盘ArrowDown
事件提供以下侦听器(其密钥代码为40
):
window.onload = function() {
var itemsContainer = document.getElementById('cities-drop');
document.addEventListener('keyup',function(event){
if (event.keyCode == 40 && itemsContainer.style.display=='block') {
event.preventDefault();
for (var i=0;i<itemsContainer.children.length-1;i++){
if (itemsContainer.getAttribute('class').substr('hovered')!=-1){
itemsContainer.children[i].setAttribute('class','');
itemsContainer.children[i].nextSibling.setAttribute('class','hovered');
//break;
}
}
}
});
在这种情况下,hovering
在按下ArrowDown
后跳转到列表中的最后一个元素。
如果取消注释break
,它会跳转到第二个元素并且不再跳跃。
无法得到原则,该怎么做,听众总是倾听......
修改
live demo
或许,这是关闭的问题,但我不确定
答案 0 :(得分:4)
在查看您的代码并了解您要执行的操作后,我认为您的错误是使用substr
,您应该使用indexOf
。这是更新的行:
if (itemsContainer.getAttribute('class').indexOf('hovered') != -1)
substr
为start
索引的字符串值。不知道结果会是什么,但显然它不是-1,因为条件每次都返回true,导致下一个元素每次都被徘徊,一直到列表的底部。在那里有break
语句,它在第一个元素处执行if语句(导致第二个元素'悬停'),然后退出。
我会在更正你的代码之后将break
语句保留在那里,以便循环在找到匹配后停止,并且不会不必要地遍历其余项目。
<小时/> 修改强>
我在您的代码中也发现了其他几个问题。这是一个适用于IE和FF的示例,至少(尚未在Safari,Opera或Chrome中测试过):
<html>
<head>
<style type="text/css">
.hovered
{
color:red;
}
</style>
<script type="text/JavaScript">
function move(event)
{
var itemsContainer = document.getElementById('cities-drop');
if (event.keyCode == 40 && itemsContainer.style.display == 'block')
{
if (event.preventDefault)
event.preventDefault();
if (event.cancelBubble)
event.cancelBubble();
if (event.stopImmediatePropagation)
event.stopImmediatePropagation();
for (var i=0; i<itemsContainer.children.length-1; i++)
{
if (itemsContainer.children[i].className.indexOf('hovered') != -1)
{
itemsContainer.children[i].className = "";
itemsContainer.children[i+1].className = "hovered";
break;
}
}
}
};
</script>
</head>
<body onkeydown="move(event)">
<div id="cities-drop" style="display:block;">
<p class="hovered">Item 1</p>
<p>Item 2</p>
<p>Item 3</p>
<p>Item 4</p>
<p>Item 5</p>
<p>Item 6</p>
<p>Item 7</p>
</div>
</body>
</html>
<小时/> 详细信息:对我来说,在IE9中,函数从未被调用过。相反,我只是将其设为常规功能,并在
onkeydown
标记中添加了body
个事件。
接下来,为了实现跨浏览器兼容性,您应该在使用之前检查以确保event.preventDefault
存在。我在IE中遇到了JS错误。
在你的if语句中,你有itemsContainer.getAttribute('class')
。首先,您需要使用itemsContainer.children[i]
。其次,.getAttribute('class')
在IE中不适用于我,因此我将其切换为.className
。
最后,itemsContainer.children[i].nextSibling
对我不起作用,但只需将其更改为itemsContainer.children[i+1]
即可获得下一个兄弟。
答案 1 :(得分:3)
我可以看到一些可能存在问题的事情。首先,你更新
itemsContainer.children[i].nextSibling
itemsContainer.children[i+1]
。这就是为什么总是你跳过休息时选择的最后一个元素。如果有与该类匹配的项目,itemsComtainer [i + 1]将始终悬停。
第二个问题是Travesty3在答案中指出的问题。
我还更改了if条件,以检查hovered类是否在其中一个子节点而不是容器本身。
if (itemsContainer.children[i].getAttribute('class').match('hovered'))
我使用以下代码行修改了事件处理程序,这似乎工作正常:
document.addEventListener('keyup',function(event){
if (event.keyCode === 40 && itemsContainer.style.display==='block') {
event.preventDefault();
for (var i=0,l=itemsContainer.children.length;i<l;++i){
if (itemsContainer.children[i].getAttribute('class').match('hovered')){
itemsContainer.children[i].setAttribute('class','');
itemsContainer.children[i+1].setAttribute('class','hovered');
break;
}
}
}
});
请记住,制作这样的下拉控件是相当多的工作。用户希望使用键盘进行导航。为了获得出色的用户体验,您应该处理许多键,例如箭头键,用于聚焦控件的选项卡,用于打开和关闭控件的空间,用于聚焦于第一个匹配元素的字母数字输入等。
如果用户体验很重要,我建议使用框架和插件。我个人更喜欢jquery和jquery ui,并且有一些用于选择下拉的插件。另一个优点是,如果客户端禁用了javascript,或者由于某种原因你的javascript会出错,那么大多数插件都会回归到常规的原生select元素,这仍然会在功能上运行良好。
我自己使用这个插件作为一个简单的下拉菜单: http://www.abeautifulsite.net/blog/2011/01/jquery-selectbox-plugin/
编辑:我正在撤消此建议,因为如果多个元素具有相同的名称,它将无效。如果这很重要,您应该查看Filament Group的selectmenu插件: http://filamentgroup.com/lab/jquery_ui_selectmenu_an_aria_accessible_plugin_for_styling_a_html_select/ 的 //修改
...并且组合框的jquery自动完成插件也支持书面输入: http://jqueryui.com/demos/autocomplete/
答案 2 :(得分:3)
您可以尝试更简单的方法,而不是使用循环:
window.onload = function() {
var itemsContainer = document.getElementById('cities-drop');
document.addEventListener('keyup',function(event) {
if (event.keyCode == 40 && itemsContainer.style.display=='block') {
event.preventDefault();
var previousHoveredChoice = itemsContainer.querySelector('.hovered');
previousHoveredChoice.className = '';
var currentHoveredChoice = previousHoveredChoice.nextSibling;
if (currentHoveredChoice) {
currentHoveredChoice.className = 'hovered';
}
}
});
//following code is copy-pasted from the live example
//just to close the onload function handler in this solution
document.addEventListener('keyup',function(event){
if (event.keyCode == 27) {
if (document.getElementById('cities-drop').style.display=='block'){
document.getElementById('cities-drop').style.display='none';
}
}
});
//end of copy-pasted code
};