JQuery - 在 Firefox 和 IE 中通过 Tab 导航时焦点不起作用
JQuery - Focus not working when navigating via Tab in Firefox and IE
我有一个简单的导航栏,我打算在所有可通过键盘访问的导航栏中使用它。导航栏应该像这样工作:
使用 Tab 键,您应该能够浏览每个
导航类别及其元素。
使用 右* 和 **左 键,您只能浏览导航类别。
使用向下键还可以打开导航类别。
使用 ESC 键关闭(隐藏)当前可见的导航类别。
下面是我开发的jsFiddle。
为简单起见,请关注 JavaScript 代码,因为 HTML 代码由于我无法控制的需求原因无法更改。我认为问题在于 Firefox/IE 处理 focus
事件的方式与 Chrome.
不同
$(document).ready(function(){
var utilitymenu = new menuBar("#utility-nav"),
navInner = new menuBar("#nav-inner"),
mainHeader = $(".main-header");
// Adding tabindex to all clickable anchor links
mainHeader.find("a").each(function(i, elem){
$(elem).attr("tabindex", i+1);
});
});
function menuBar(id){
var linksBlock = id + " > li",
linksBlockSelector = " > li",
submenuHeader = linksBlock + " > a",
submenu = linksBlock + " div[class*='sub-menu']",
submenuSelector = "div[class*='sub-menu']",
textBlock = submenu + " > ul",
textBlockSelector = submenuSelector + " > ul",
submenuElem = textBlock + " > li a",
keepMenuClosed = false;
// Adding ARIA attributes to the different sections of the navigation menus
$(linksBlock).attr({
"role": "navigation",
"aria-haspopup": "true",
"aria-labelledby": "menu-title",
"aria-describedby": "menu-description"
});
$(submenuHeader).attr({
"aria-haspopup": "true",
"id": "menu-title"
});
$(submenuHeader).each(function(i, elem){
$(elem).attr("aria-label", $(elem).text().trim());
});
$(submenu).attr({
"tabindex": "-1",
"id": "menu-description"
});
$(textBlock).attr({
"aria-expanded": "false",
"aria-hidden": "true"
});
// Hides visible menus when clicking outside the menu area
$(document).click(function(event) {
if(!$(event.target).closest().length){
$(submenu + ":visible").hide().find(textBlock).attr("aria-expanded", "false");
$(submenu + ":visible").hide().find(textBlock).attr("aria-hidden", "true");
}
});
// Drop Down Menu event handler (not inner elements)
$(linksBlock)
.focus(function(){
if($(this).find(submenuSelector).is(":hidden") && !keepMenuClosed){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "true");
$(this).find(textBlockSelector).attr("aria-hidden", "false");
keepDropdownClosed = false;
}
else if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
}
})
.mouseover(function(){
$(this).find(submenuSelector).show();
$(this).find(textBlockSelector).attr("aria-expanded", "true");
$(this).siblings().find(submenuSelector).hide();
$(this).siblings().find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
})
.mouseout(function(){
$(this).find(submenuSelector).hide();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
})
.keydown(function(event){
switch(event.keyCode){
//tab key
case 9:
keepMenuClosed = true;
if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
}
else if($(this).find(submenuSelector).is(":hidden")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "true");
$(this).find(textBlockSelector).attr("aria-hidden", "false");
}
break;
// esc key
case 27:
if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
$(this).closest(linksBlock).focus();
}
break;
// key left
case 37:
if($(this).find(submenuSelector).is(":hidden")){
$(this).prev().find(" > a").focus();
keepMenuClosed = true;
}
break;
// key right
case 39:
if($(this).find(submenuSelector).is(":hidden")){
$(this).next().find(" > a").focus();
keepMenuClosed = true;
}
break;
// key up/down
case 38, 40:
event.preventDefault();
$(this).find(submenuSelector).show();
break;
}
});
// Sub Menu Elements keyboard handler
$(submenuElem)
.keydown(function(event){
switch(event.keyCode){
// tab key
case 9:
$(this).parent().next().find("a").focus();
break;
// esc key
case 27:
if($(this).closest(submenuSelector).is(":visible")){
$(this).closest("div").siblings("a ").focus();
}
break;
// key up
case 38:
event.preventDefault();
$(this).parent().prev().find("a").focus();
break;
// key down
case 40:
event.preventDefault();
$(this).parent().next().find("a").focus();
break;
}
});
}
TLDR
我只想了解为什么导航仅在 Chrome 中有效,而在 IE 和 Firefox 中无效。 wrong/not 我在这里干什么?我一直在查看 IE/FF focus
、preventDefault
的已知问题,但无济于事。我不认为我的 ARIA 代码导致了问题,但我准备好探索所有建议!
编辑
根据@Adam的建议,我添加了以下代码来显示我在Firefox/IE上遇到的问题:
$(this).keydown(function(e){
if(e.keyCode === 9){
alert($(':focus').toArray());
}
});
它揭示了问题的根源。我目前正在努力修改我的代码,以更好地区分我如何听键盘敲击;以及在关注我的元素时表现出更好的聆听效果。
隐藏元素时,它会失去焦点
当您在 submenuElem
上按下 tab
键时,事件也会被 linksBlock
拦截
出于这个特定原因,当您使用以下行时
$(this).parent().next().find("a").focus();
它触发 focus() 事件,然后执行将隐藏子菜单的切换。这里焦点丢失了。
$(linksBlock)
.focus(function(){
[...]
else if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
然后,第二个事件被触发到主要块,它将显示没有设置焦点的隐藏元素:
$(linksBlock)
.keydown(function(event){
[...]
else if($(this).find(submenuSelector).is(":hidden")){
$(this).find(submenuSelector).toggle();
我有一个简单的导航栏,我打算在所有可通过键盘访问的导航栏中使用它。导航栏应该像这样工作:
使用 Tab 键,您应该能够浏览每个 导航类别及其元素。
使用 右* 和 **左 键,您只能浏览导航类别。
使用向下键还可以打开导航类别。
使用 ESC 键关闭(隐藏)当前可见的导航类别。
下面是我开发的jsFiddle。
为简单起见,请关注 JavaScript 代码,因为 HTML 代码由于我无法控制的需求原因无法更改。我认为问题在于 Firefox/IE 处理 focus
事件的方式与 Chrome.
$(document).ready(function(){
var utilitymenu = new menuBar("#utility-nav"),
navInner = new menuBar("#nav-inner"),
mainHeader = $(".main-header");
// Adding tabindex to all clickable anchor links
mainHeader.find("a").each(function(i, elem){
$(elem).attr("tabindex", i+1);
});
});
function menuBar(id){
var linksBlock = id + " > li",
linksBlockSelector = " > li",
submenuHeader = linksBlock + " > a",
submenu = linksBlock + " div[class*='sub-menu']",
submenuSelector = "div[class*='sub-menu']",
textBlock = submenu + " > ul",
textBlockSelector = submenuSelector + " > ul",
submenuElem = textBlock + " > li a",
keepMenuClosed = false;
// Adding ARIA attributes to the different sections of the navigation menus
$(linksBlock).attr({
"role": "navigation",
"aria-haspopup": "true",
"aria-labelledby": "menu-title",
"aria-describedby": "menu-description"
});
$(submenuHeader).attr({
"aria-haspopup": "true",
"id": "menu-title"
});
$(submenuHeader).each(function(i, elem){
$(elem).attr("aria-label", $(elem).text().trim());
});
$(submenu).attr({
"tabindex": "-1",
"id": "menu-description"
});
$(textBlock).attr({
"aria-expanded": "false",
"aria-hidden": "true"
});
// Hides visible menus when clicking outside the menu area
$(document).click(function(event) {
if(!$(event.target).closest().length){
$(submenu + ":visible").hide().find(textBlock).attr("aria-expanded", "false");
$(submenu + ":visible").hide().find(textBlock).attr("aria-hidden", "true");
}
});
// Drop Down Menu event handler (not inner elements)
$(linksBlock)
.focus(function(){
if($(this).find(submenuSelector).is(":hidden") && !keepMenuClosed){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "true");
$(this).find(textBlockSelector).attr("aria-hidden", "false");
keepDropdownClosed = false;
}
else if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
}
})
.mouseover(function(){
$(this).find(submenuSelector).show();
$(this).find(textBlockSelector).attr("aria-expanded", "true");
$(this).siblings().find(submenuSelector).hide();
$(this).siblings().find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
})
.mouseout(function(){
$(this).find(submenuSelector).hide();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
})
.keydown(function(event){
switch(event.keyCode){
//tab key
case 9:
keepMenuClosed = true;
if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
}
else if($(this).find(submenuSelector).is(":hidden")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "true");
$(this).find(textBlockSelector).attr("aria-hidden", "false");
}
break;
// esc key
case 27:
if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
$(this).find(textBlockSelector).attr("aria-expanded", "false");
$(this).find(textBlockSelector).attr("aria-hidden", "true");
$(this).closest(linksBlock).focus();
}
break;
// key left
case 37:
if($(this).find(submenuSelector).is(":hidden")){
$(this).prev().find(" > a").focus();
keepMenuClosed = true;
}
break;
// key right
case 39:
if($(this).find(submenuSelector).is(":hidden")){
$(this).next().find(" > a").focus();
keepMenuClosed = true;
}
break;
// key up/down
case 38, 40:
event.preventDefault();
$(this).find(submenuSelector).show();
break;
}
});
// Sub Menu Elements keyboard handler
$(submenuElem)
.keydown(function(event){
switch(event.keyCode){
// tab key
case 9:
$(this).parent().next().find("a").focus();
break;
// esc key
case 27:
if($(this).closest(submenuSelector).is(":visible")){
$(this).closest("div").siblings("a ").focus();
}
break;
// key up
case 38:
event.preventDefault();
$(this).parent().prev().find("a").focus();
break;
// key down
case 40:
event.preventDefault();
$(this).parent().next().find("a").focus();
break;
}
});
}
TLDR
我只想了解为什么导航仅在 Chrome 中有效,而在 IE 和 Firefox 中无效。 wrong/not 我在这里干什么?我一直在查看 IE/FF focus
、preventDefault
的已知问题,但无济于事。我不认为我的 ARIA 代码导致了问题,但我准备好探索所有建议!
编辑
根据@Adam的建议,我添加了以下代码来显示我在Firefox/IE上遇到的问题:
$(this).keydown(function(e){
if(e.keyCode === 9){
alert($(':focus').toArray());
}
});
它揭示了问题的根源。我目前正在努力修改我的代码,以更好地区分我如何听键盘敲击;以及在关注我的元素时表现出更好的聆听效果。
隐藏元素时,它会失去焦点
当您在 submenuElem
上按下 tab
键时,事件也会被 linksBlock
出于这个特定原因,当您使用以下行时
$(this).parent().next().find("a").focus();
它触发 focus() 事件,然后执行将隐藏子菜单的切换。这里焦点丢失了。
$(linksBlock)
.focus(function(){
[...]
else if($(this).find(submenuSelector).is(":visible")){
$(this).find(submenuSelector).toggle();
然后,第二个事件被触发到主要块,它将显示没有设置焦点的隐藏元素:
$(linksBlock)
.keydown(function(event){
[...]
else if($(this).find(submenuSelector).is(":hidden")){
$(this).find(submenuSelector).toggle();