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中是为了不让这个问题混乱。另外,你在那里可以更好地测试它。

CODEPEN DEMO HERE

p.s。此外,我在其中一个选项卡中使用了一个小型 Bootstrap 手风琴。 (为简单起见,未在演示中显示)。因此,如果您想到可以全局修复所有 Bootstrap 功能而不是仅修复导航选项卡的修复程序,我将更加感激,但我并不期待它。

提前致谢

问题出在 CodePen 中代码末尾的事件处理程序:

$(this).click(function(e){
    e.stopPropagation();
});

这明确地阻止了菜单选项卡上的点击冒泡到任何其他事件处理程序。可能 Bootstrap 选项卡代码将其事件处理程序绑定在 DOM.

的顶部

不清楚该代码的意图是什么;它没有被注释,并且从查看其余代码时也看不出来。它可能只是一个无偿添加,在这种情况下,鉴于该代码的性质,它是错误的。