jQuery 2.1 | Навигация по несмежным ссылкам в списке с помощью клавиш со стрелками

Я хочу перемещаться с помощью клавиш со стрелками в списке, который содержит ссылки того же класса, заключенные в some li, примерно так:

<ul>
<li class="linkTitle">LINKS BELOW</li>
<li class="linkHolder"><a class="link">LINK</a></li>
<li class="linkHolder"><a class="link">LINK</a></li>
<li class="linkTitle">LINKS BELOW</li>
<li class="linkHolder"><a class="link">LINK</a></li>
<li class="linkHolder"><a class="link">LINK</a></li>
<li class="linkHolder"><a class="link">LINK</a></li>
<li class="linkHolder"><a class="link">LINK</a></li>
</ul>

Приведенный ниже код отлично работает для непрерывных ссылок и циклически перемещается вверх или вниз по списку, однако он ломается при столкновении с li, который не содержит ссылки.

$(function() {

    var $li = $('li'),
        
    $move = $(".move").click(function () {
        this.focus();
    });
    
    $(document).keydown(function(e) {
        if (e.keyCode == 40 || e.keyCode == 38) {
            var inc = e.keyCode == 40 ? 1 : -1,
                move = $move.filter(":focus").parent('li').index() + inc;
            $li.eq(move % $li.length).find('.move').focus();
        }
    });
    
    $move.filter(':first').focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul>
    <li>
        <a href="#" class='move'>Link</a>
    </li>
    <li>
        <a href="#" class='move'>Link</a>
    </li>
    <li>
        <a href="#" class='move'>Link</a>
    </li>
    <li>
        <a href="#" class='move'>Link</a>
    </li>
    <li>
        <a href="#" class='move'>Link</a>
    </li>
    <li>
        <a href="#" class='move'>Link</a>
    </li>
    
</ul>

Я пытался, но не могу заставить его работать с несмежными ссылками. Решение, в котором вы можете перемещаться (и циклически) только по ссылкам одного класса, независимо от количества и положения несвязанных li в списке, было бы мне по душе!

ОБНОВЛЕНИЕ

Вот DEMO над чем я работаю, UP Клавиша со стрелкой работает по назначению, но останавливает фокус один раз в верхней части списка. Клавиша со стрелкой ВНИЗ перемещает фокус вниз списка. Циклическое переключение по ссылкам тоже не работает. В этом примере, nextAll() и prevAll(), похоже, делают свое дело, когда встречают li без ссылки.


person koolness    schedule 10.10.2014    source источник
comment
Разве табуляция не сделает это без кода?   -  person j08691    schedule 11.10.2014
comment
@ j08691 j08691 Я избегаю tabIndex в этом массиве ссылок списка, так как мой пользовательский интерфейс использует навигацию с помощью клавиш со стрелками. Клавиши со стрелками влево и вправо будут циклически перемещать фокус по заголовкам контейнеров ссылок, а клавиши со стрелками вверх и вниз будут циклически перемещать фокус по содержимому ссылок в этих контейнерах. Я не хочу поддерживать значения tabIndex в динамически добавляемом списке/ссылках.   -  person koolness    schedule 11.10.2014


Ответы (1)


Вот РЕШЕНИЕ, которое я придумал на основе этого ответа из Stackoverflow. Упомянутые выше несвязанные критерии li моделируются с помощью блочного элемента, вставленного между неупорядоченными списками. Навигация по меню основана на функциональности клавиши доступа (клавиша доступа + z); клавиши со стрелками; Клавиша табуляции (частичная); или мышь. Как только любой UL выделен (выделен), клавиши со стрелками влево и вправо позволяют перемещаться по UL, а клавиши со стрелками вверх и вниз позволяют перемещаться по каждому элементу в выделенном UL. Я добавил CSS, чтобы различать, какие UL/li сфокусированы:

CSS

body {-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;}

p {margin-top:10px;margin-left:4px;}
.ulholder{width:160px;height:200px;background:#AAA}
ul {background:#AAA}
ul.focused {background:#999}
ul:hover, ul:focus, ul:active {background:#999;}

li.selected {background:darkblue}
li:hover, li:focus, li:active {background:orange;}
li:hover a, li:focus a, li:active a {color:white;}
.list{cursor:pointer;}
.link {margin-left:10px;font-weight:bold;text-decoration:none;color:darkblue}
.link:hover, .link:focus, .link:active {color:white;}
.linkfocused {color:white;}

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<div class="ulholder"><p class="label">List 1</p>
<ul accesskey="z" tabindex="0">
<li class="list"><a href="#" tabindex="-1" class="link">Item 1</a></li>
<li class="list"><a href="#" tabindex="-1" class="link">Item 2</a></li>
<li class="list"><a href="#" tabindex="-1" class="link">Item 3</a></li>
</ul>
<p class="label">List 2</p>
<ul tabindex="0">
<li class="list"><a href="#" tabindex="-1" class="link">Item 1</a></li>
<li class="list"><a href="#" tabindex="-1" class="link">Item 2</a></li>
<li class="list"><a href="#" tabindex="-1" class="link">Item 3</a></li>
</ul>
</div>

JQUERY

var $liSelected;
var $ulSelected;

$(function(){

$(document).keydown(function(e) {
 // Make sure we have a ul selected

if($ulSelected) {

   if(e.which === 37) { // left arrow
   $('ul').prev().prev().addClass('focused').focus();
   }
   if(e.which === 39) { // right arrow
   $('ul').next().next().addClass('focused').focus();
   }

   if(e.which === 40) { // down arrow
   if($liSelected) {
   $liSelected.removeClass('selected');
   $liSelected.children('.link').blur();
   var $next = $liSelected.next('.list');

   if($next.length) {
   $liSelected = $next.addClass('selected');
   $next.children('.link').focus();

   } else {
   $liSelected = $ulSelected.children('li').first('.list').addClass('selected'); 
   $ulSelected.children('li').first('.list').children('.link').focus();
     }

   } else {
   $liSelected = $ulSelected.children('li').first('.list').addClass('selected');
   $ulSelected.children('li').first('.list').children('.link').focus();
     }

   } else if(e.which === 38) { // up arrow

   if($liSelected) {
   $liSelected.removeClass('selected');
   $liSelected.children('.link').blur();
   var $prev = $liSelected.prev('.list');

   if($prev.length) {
   $liSelected = $prev.addClass('selected');
   $prev.children('.link').focus();

   } else {

   $liSelected = $ulSelected.children('li').last('.list').addClass('selected');
   $ulSelected.children('li').last('.list').children('.link').focus();
     }

   } else {
   $liSelected = $ulSelected.children('li').last('.list').addClass('selected');
   $ulSelected.children('li').last('.list').children('.link').focus();
      }
   }

  }
});

$('ul .link').on('click focus', function() {
$('ul').removeClass('focused');
$('ul').find('.list').removeClass('selected');
$('ul').find('.link').removeClass('listfocused');
$(this).parent().addClass('selected');
$(this).parent().parent('ul').addClass('focused');
});

$('ul .list').on('click', function(){
$('.list').removeClass('selected');
$('.link').removeClass('linkfocused');
$(this).addClass('selected');
$(this).children('.link').focus().click().addClass('linkfocused');
});

$('ul').on('focus', function(e) {
$('ul .link').removeClass('linkfocused');
$('ul .list').removeClass('selected');
$('ul').removeClass('focused');
$ulSelected = $(this);
$(this).addClass('focused');
$liSelected = false;
});

});
person koolness    schedule 13.10.2014