Javascript 与 Bootstrap 功能冲突
Javascript conflicts with Bootstrap functionality
我正在构建一个包含 Bootstrap 导航选项卡部分的站点。问题是我的开发团队正在实施与 Bootstrap 冲突的可访问性 javascript。我将 link 附加到显示问题的 codepen。 (见下文)。它基本上是导航选项卡根本不起作用。没有发生点击事件。
我在辅助功能脚本方面没有太多经验,但我希望这里有人可以告诉我如何使 bootstrap 工作而不丢失此辅助功能脚本提供的功能。
该脚本旨在允许使用屏幕阅读器(即 JAWS)的视力不佳的用户能够根据 JAWS 通过阅读 ARIAS 和浏览 ROLES 告诉他们的内容在菜单和屏幕项目周围切换。
Javascript如下:
$(function(){
$('.nav').setup_navigation();
});
var keyCodeMap = {
48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9", 59:";",
65:"a", 66:"b", 67:"c", 68:"d", 69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l",
77:"m", 78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v", 87:"w", 88:"x", 89:"y", 90:"z",
96:"0", 97:"1", 98:"2", 99:"3", 100:"4", 101:"5", 102:"6", 103:"7", 104:"8", 105:"9"
}
$.fn.setup_navigation = function(settings) {
settings = jQuery.extend({
menuHoverClass: 'main-menu-item',
}, settings
);
// Add ARIA role to menubar and menu items
$(this).attr('role', 'menubar').find('li').attr('role', 'menuitem');
var top_level_links = $(this).find('> li > a');
//// Set tabIndex to -1 so that top_level_links can't receive focus until menu is open
//$(top_level_links).next('ul')
//.attr({ 'aria-hidden': 'true', 'role': 'menu' })
//.find('a');
// Adding aria-haspopup for appropriate items
$(top_level_links).each(function(){
if($(this).next('ul').length > 0)
$(this).parent('li').attr('aria-haspopup', 'true');
});
$(top_level_links).each(function(){
if($(this).next('ul').length > 0)
$(this).parent('ul').attr('aria-haspopup', 'true');
});
$(top_level_links).hover(function(){
$(this).closest('ul')
.attr('aria-hidden', 'false')
.find('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
$(this).next('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0);
});
$(top_level_links).focus(function(){
$(this).closest('ul')
.attr('aria-hidden', 'false')
.find('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',1);
$(this).next('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0);
});
// Bind arrow keys for navigation
$(top_level_links).keydown(function(e){
if(e.keyCode == 37) {
e.preventDefault();
// This is the first item
if($(this).parent('li').prev('li').length == 0) {
$(this).parents('ul').find('> li').last().find('a').first().focus();
} else {
$(this).parent('li').prev('li').find('a').first().focus();
}
} else if(e.keyCode == 38) {
e.preventDefault();
if($(this).parent('li').find('ul').length > 0) {
$(this).parent('li').find('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0)
.last().focus();
}
} else if(e.keyCode == 39) {
e.preventDefault();
// This is the last item
if($(this).parent('li').next('li').length == 0) {
$(this).parents('ul').find('> li').first().find('a').first().focus();
} else {
$(this).parent('li').next('li').find('a').first().focus();
}
} else if(e.keyCode == 40) {
e.preventDefault();
if($(this).parent('li').find('ul').length > 0) {
$(this).parent('li').find('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0)
.first().focus();
}
} else if(e.keyCode == 13 || e.keyCode == 32) {
// If submenu is hidden, open it
//e.preventDefault();
$(this).parent('li').find('ul[aria-hidden=true]')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0)
.first().focus();
} else if(e.keyCode == 27) {
e.preventDefault();
$('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
} else {
$(this).parent('li').find('ul[aria-hidden=false] a').each(function(){
if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
$(this).focus();
return false;
}
});
}
});
var links = $(top_level_links).parent('li').find('ul').find('a');
$(links).keydown(function(e){
if(e.keyCode == 38) {
e.preventDefault();
// This is the first item
if($(this).parent('li').prev('li').length == 0) {
$(this).parents('ul').parents('li').find('a').first().focus();
} else {
$(this).parent('li').prev('li').find('a').first().focus();
}
} else if(e.keyCode == 40) {
e.preventDefault();
if($(this).parent('li').next('li').length == 0) {
$(this).parents('ul').parents('li').find('a').first().focus();
} else {
$(this).parent('li').next('li').find('a').first().focus();
}
} else if(e.keyCode == 27 || e.keyCode == 37) {
e.preventDefault();
$(this)
.parents('ul').first()
.prev('a').focus()
.parents('ul').first().find('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
} else if(e.keyCode == 32) {
e.preventDefault();
window.location = $(this).attr('href');
} else {
var found = false;
$(this).parent('li').nextAll('li').find('a').each(function(){
if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
$(this).focus();
found = true;
return false;
}
});
if(!found) {
$(this).parent('li').prevAll('li').find('a').each(function(){
if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
$(this).focus();
return false;
}
});
}
}
});
//Hide menu if click or focus occurs outside of navigation
$(this).find('a').last().keydown(function(e){
if(e.keyCode == 9) {
// If the user tabs out of the navigation hide all menus
$('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
}
});
$(document).click(function () {
$('.' + settings.menuHoverClass).attr('aria-hidden', 'true').removeClass(settings.menuHoverClass).find('a').attr('tabIndex', 0);
});
$(this).click(function(e){
e.stopPropagation();
});
}
HTML在附笔link中是为了不让这个问题混乱。另外,你在那里可以更好地测试它。
p.s。此外,我在其中一个选项卡中使用了一个小型 Bootstrap 手风琴。 (为简单起见,未在演示中显示)。因此,如果您想到可以全局修复所有 Bootstrap 功能而不是仅修复导航选项卡的修复程序,我将更加感激,但我并不期待它。
提前致谢
问题出在 CodePen 中代码末尾的事件处理程序:
$(this).click(function(e){
e.stopPropagation();
});
这明确地阻止了菜单选项卡上的点击冒泡到任何其他事件处理程序。可能 Bootstrap 选项卡代码将其事件处理程序绑定在 DOM.
的顶部
不清楚该代码的意图是什么;它没有被注释,并且从查看其余代码时也看不出来。它可能只是一个无偿添加,在这种情况下,鉴于该代码的性质,它是错误的。
我正在构建一个包含 Bootstrap 导航选项卡部分的站点。问题是我的开发团队正在实施与 Bootstrap 冲突的可访问性 javascript。我将 link 附加到显示问题的 codepen。 (见下文)。它基本上是导航选项卡根本不起作用。没有发生点击事件。
我在辅助功能脚本方面没有太多经验,但我希望这里有人可以告诉我如何使 bootstrap 工作而不丢失此辅助功能脚本提供的功能。
该脚本旨在允许使用屏幕阅读器(即 JAWS)的视力不佳的用户能够根据 JAWS 通过阅读 ARIAS 和浏览 ROLES 告诉他们的内容在菜单和屏幕项目周围切换。
Javascript如下:
$(function(){
$('.nav').setup_navigation();
});
var keyCodeMap = {
48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9", 59:";",
65:"a", 66:"b", 67:"c", 68:"d", 69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l",
77:"m", 78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v", 87:"w", 88:"x", 89:"y", 90:"z",
96:"0", 97:"1", 98:"2", 99:"3", 100:"4", 101:"5", 102:"6", 103:"7", 104:"8", 105:"9"
}
$.fn.setup_navigation = function(settings) {
settings = jQuery.extend({
menuHoverClass: 'main-menu-item',
}, settings
);
// Add ARIA role to menubar and menu items
$(this).attr('role', 'menubar').find('li').attr('role', 'menuitem');
var top_level_links = $(this).find('> li > a');
//// Set tabIndex to -1 so that top_level_links can't receive focus until menu is open
//$(top_level_links).next('ul')
//.attr({ 'aria-hidden': 'true', 'role': 'menu' })
//.find('a');
// Adding aria-haspopup for appropriate items
$(top_level_links).each(function(){
if($(this).next('ul').length > 0)
$(this).parent('li').attr('aria-haspopup', 'true');
});
$(top_level_links).each(function(){
if($(this).next('ul').length > 0)
$(this).parent('ul').attr('aria-haspopup', 'true');
});
$(top_level_links).hover(function(){
$(this).closest('ul')
.attr('aria-hidden', 'false')
.find('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
$(this).next('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0);
});
$(top_level_links).focus(function(){
$(this).closest('ul')
.attr('aria-hidden', 'false')
.find('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',1);
$(this).next('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0);
});
// Bind arrow keys for navigation
$(top_level_links).keydown(function(e){
if(e.keyCode == 37) {
e.preventDefault();
// This is the first item
if($(this).parent('li').prev('li').length == 0) {
$(this).parents('ul').find('> li').last().find('a').first().focus();
} else {
$(this).parent('li').prev('li').find('a').first().focus();
}
} else if(e.keyCode == 38) {
e.preventDefault();
if($(this).parent('li').find('ul').length > 0) {
$(this).parent('li').find('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0)
.last().focus();
}
} else if(e.keyCode == 39) {
e.preventDefault();
// This is the last item
if($(this).parent('li').next('li').length == 0) {
$(this).parents('ul').find('> li').first().find('a').first().focus();
} else {
$(this).parent('li').next('li').find('a').first().focus();
}
} else if(e.keyCode == 40) {
e.preventDefault();
if($(this).parent('li').find('ul').length > 0) {
$(this).parent('li').find('ul')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0)
.first().focus();
}
} else if(e.keyCode == 13 || e.keyCode == 32) {
// If submenu is hidden, open it
//e.preventDefault();
$(this).parent('li').find('ul[aria-hidden=true]')
.attr('aria-hidden', 'false')
.addClass(settings.menuHoverClass)
.find('a').attr('tabIndex',0)
.first().focus();
} else if(e.keyCode == 27) {
e.preventDefault();
$('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
} else {
$(this).parent('li').find('ul[aria-hidden=false] a').each(function(){
if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
$(this).focus();
return false;
}
});
}
});
var links = $(top_level_links).parent('li').find('ul').find('a');
$(links).keydown(function(e){
if(e.keyCode == 38) {
e.preventDefault();
// This is the first item
if($(this).parent('li').prev('li').length == 0) {
$(this).parents('ul').parents('li').find('a').first().focus();
} else {
$(this).parent('li').prev('li').find('a').first().focus();
}
} else if(e.keyCode == 40) {
e.preventDefault();
if($(this).parent('li').next('li').length == 0) {
$(this).parents('ul').parents('li').find('a').first().focus();
} else {
$(this).parent('li').next('li').find('a').first().focus();
}
} else if(e.keyCode == 27 || e.keyCode == 37) {
e.preventDefault();
$(this)
.parents('ul').first()
.prev('a').focus()
.parents('ul').first().find('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
} else if(e.keyCode == 32) {
e.preventDefault();
window.location = $(this).attr('href');
} else {
var found = false;
$(this).parent('li').nextAll('li').find('a').each(function(){
if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
$(this).focus();
found = true;
return false;
}
});
if(!found) {
$(this).parent('li').prevAll('li').find('a').each(function(){
if($(this).text().substring(0,1).toLowerCase() == keyCodeMap[e.keyCode]) {
$(this).focus();
return false;
}
});
}
}
});
//Hide menu if click or focus occurs outside of navigation
$(this).find('a').last().keydown(function(e){
if(e.keyCode == 9) {
// If the user tabs out of the navigation hide all menus
$('.'+settings.menuHoverClass)
.attr('aria-hidden', 'true')
.removeClass(settings.menuHoverClass)
.find('a')
//.attr('tabIndex',-1);
}
});
$(document).click(function () {
$('.' + settings.menuHoverClass).attr('aria-hidden', 'true').removeClass(settings.menuHoverClass).find('a').attr('tabIndex', 0);
});
$(this).click(function(e){
e.stopPropagation();
});
}
HTML在附笔link中是为了不让这个问题混乱。另外,你在那里可以更好地测试它。
p.s。此外,我在其中一个选项卡中使用了一个小型 Bootstrap 手风琴。 (为简单起见,未在演示中显示)。因此,如果您想到可以全局修复所有 Bootstrap 功能而不是仅修复导航选项卡的修复程序,我将更加感激,但我并不期待它。
提前致谢
问题出在 CodePen 中代码末尾的事件处理程序:
$(this).click(function(e){
e.stopPropagation();
});
这明确地阻止了菜单选项卡上的点击冒泡到任何其他事件处理程序。可能 Bootstrap 选项卡代码将其事件处理程序绑定在 DOM.
的顶部不清楚该代码的意图是什么;它没有被注释,并且从查看其余代码时也看不出来。它可能只是一个无偿添加,在这种情况下,鉴于该代码的性质,它是错误的。