Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   tabindex native javascript (https://javascript.ru/forum/dom-window/74525-tabindex-native-javascript.html)

s24344 18.07.2018 12:39

tabindex native javascript
 
Ребята, подскажите, пожалуйста, как мне решить следующую задачу:

У меня есть некий список элементов:
ul.nav__list
  li.nav__item
    a.nav__item-link
      span Players
  li.nav__item
    a.nav__item-link
      span Coaches
  li.nav__item
    a.nav__item-link
      span Refereed

div.navigation
  a(href="#") Navigation

Мне необходимо реализовать следующий функционал.
После загрузки документа, при нажатии на клавишу Tab, ссылки поочередно получают focus. Мне необходимо, чтобы порядок был слудующий. После фокуса на первой ссылке:
a.nav__item-link

при следующем нажатии на кноку Tab, у меня фокус перешел на:
a(href="#") Navigation

Затем на вторую ссылку:
a.nav__item-link

А после этого сноав на:
a(href="#") Navigation

Далее на третью ссылку
a.nav__item-link

И при следующем нажатии на Tab снова на:
a(href="#") Navigation

И так далее.

И наиболее важный вопрос: как мне в момент фокуса ссылки, вызывать какой либо обработчик.
Пример логики, которую я хочу реализовать есть на следующем сайте:
http://www.kentfa.com/

Dilettante_Pro 18.07.2018 14:15

<style>
ul li { display:inline; 
    border: 1px solid gray; 
}
div a{ border: 1px solid gray; }

</style>
<ul class='nav__list'>
  <li class = 'nav__item'>
    <a href="#" class='nav__item-link'>
      <span> Players </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link'>
      <span> Coaches </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link'>
      <span> Referees </span>
    </a>
  </li>

<div class='navigation'>
  <a  href="#"><span> Navigation</span> </a>
</div>
<script>
    var flag = true, idx = 0;
    var list = document.querySelectorAll('li a');
    var nav = document.querySelector('div a');
    nav.focus();
    document.onkeydown = function(e) {
        if(e.keyCode == 9) {
           e.preventDefault();
           if(flag) { 
              list[idx].focus(); 
              // здесь можно вызвать обработчик
              idx = (idx < list.length - 1)? idx + 1: 0;
           }
           else { nav.focus(); }
           flag = !flag;
        }
    }
    document.onkeyup = function(e) { if(e.keyCode == 9) e.preventDefault(); }
</script>

s24344 19.07.2018 09:47

Спасибо. Но в данном случае мне не надо делать e.preventDefault();
А без этого функция работает не корректно.

Dilettante_Pro 19.07.2018 09:54

s24344,
Делайте e.preventDefault(); только для e.keyCode == 9

Внес изменения в пример пост 2

И обработчики можно вешать не на document.onkeydown, а на нужный вам блок, в котором лежат эти элементы - если надо, чтобы в других частях страницы TAB работал по-другому

s24344 19.07.2018 17:52

Спасибо.

s24344 20.07.2018 07:46

Вы могли бы подсказать ответ ещё на один вопрос. А если использовать событие focus, а не привязываться к onkeydown. Каким образом мне сделать такую же очередность? Например с помощью атрибута tabindex.

Dilettante_Pro 20.07.2018 10:11

Цитата:

Сообщение от s24344
с помощью атрибута tabindex.

Атрибут tabindex задает для каждого элемента только одно значение в последовательности переходов по нажатию клавиши TAB. Поэтому не получатся прыжки через раз на элемент Navigation.


Цитата:

Сообщение от s24344
А если использовать событие focus

Как вы себе это представляете? Что нужно делать при наступлении на элементе события focus?

s24344 20.07.2018 10:26

Я уже реализовал задачу с помощью вашего решения, и всё работало отлично. Но teamlead сказал, что это не вариант и надо сделать с помощью tabindex. Сейчас это реализовываю, onFocusPrimaryLink(event) { console.log(event.target); } при событии focus и динамически меняю tabindex.

Dilettante_Pro 20.07.2018 13:25

По фокусу c tabindex.
<style>
ul li { display:inline; 
    border: 1px solid gray; 
}
div a{ border: 1px solid gray; }
:focus { background-color:lightgreen;}
</style>
<ul class='nav__list'>
  <li class = 'nav__item'>
    <a href="#" class='nav__item-link' tabindex="2">
      <span> Players </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link' tabindex="4">
      <span> Coaches </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link' tabindex="6">
      <span> Referees </span>
    </a>
  </li>
</ul>
<div class='navigation'>
  <a  href="#" tabindex="1"><span> Navigation</span> </a>
</div>
<script>
    var refs = document.querySelectorAll('a');
    var list = document.querySelectorAll('li a');
    var nav = document.querySelector('div a');
    nav.focus();
    [].forEach.call(refs, function(it) {
        it.addEventListener('focus',  function() {
           var ti = +this.getAttribute('tabindex');
           if(this == nav && (ti - 1)%list.length == 0) {
                [].forEach.call(list, function(el) {
                    el.setAttribute('tabindex',(+el.getAttribute('tabindex') + list.length * 2).toString() );
                });
           }
           ti = (ti + 1).toString();
           if(this != nav) nav.setAttribute('tabindex',ti );
       });
    });
</script>

рони 20.07.2018 13:41

tab and focus
 
Цитата:

Сообщение от s24344
надо сделать с помощью tabindex.

хотел бы я видеть, как это возможно.
ниже иная вариация того, что предложил Dilettante_Pro,
<!DOCTYPE html>

<html>
<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  </head>

<body>
<style>
ul li { display:inline;
    border: 1px solid gray;
}
div a{ border: 1px solid gray; }
:focus {
    background-color: #228B22;
}

</style>
<ul class='nav__list'>
  <li class = 'nav__item'>
    <a href="#" class='nav__item-link'>
      <span> Players </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link'>
      <span> Coaches </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link'>
      <span> Referees </span>
    </a>
  </li>
</ul>
<div class='navigation' >
  <a  href="#"><span> Navigation</span> </a>
</div>
<script src="https://cdn.polyfill.io/v1/polyfill.js?Element.prototype.closest"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
    var tabindex = document.querySelectorAll("[tabindex]");
    var li = document.querySelectorAll(".nav__item");
    var nav = document.querySelector(".navigation");
    var idx = 0;
    var ln = li.length;
    [].forEach.call(tabindex, function(elem) {
        elem.removeAttribute("tabindex")
    });
    [].forEach.call(li, function(elem, i) {
        elem.setAttribute("tabindex", i);
        elem.addEventListener("click", function() {
            idx = i
        })
    });
    li[0].focus();
    nav.setAttribute("tabindex", ln);
    document.addEventListener("keydown",
        function(event) {
            if (event.keyCode == 9 && event.target.closest(".nav__item")) {
                event.preventDefault();
                nav.focus()
            } else if (event.keyCode == 9 && event.target.closest(".navigation")) {
                event.preventDefault();
                idx = ++idx % ln;
                li[idx].focus()
            }
        }, true)
});
</script>

</body>
</html>

Dilettante_Pro 20.07.2018 14:07

рони,
Цитата:

Сообщение от рони
хотел бы я видеть, как это возможно.

Таки смотрите пост 9

рони 20.07.2018 14:46

Dilettante_Pro,
ок, но я предполагал только некую секретную установку tabindex, без следующего изменения. :)

Dilettante_Pro 20.07.2018 15:03

Цитата:

Сообщение от рони
без следующего изменения

Так можно сделать только один проход (но менять tabindex элемента Navigator все равно нужно).
Если не менять tabindex у li a, то нужен в конце холостой элемент, на котором делать focus() на начало.

Dilettante_Pro 20.07.2018 15:36

Вариант, работающий также в IE и FF
<style>
ul li { display:inline; 
    border: 1px solid gray; 
}
div a{ border: 1px solid gray; }
:focus { background-color:lightgreen;}
</style>
<ul class='nav__list'>
  <li class = 'nav__item'>
    <a href="#" class='nav__item-link' tabindex="2">
      <span> Players </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link' tabindex="4">
      <span> Coaches </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link' tabindex="6">
      <span> Referees </span>
    </a>
  </li>
  <li class = 'nav__item'>
    <a  href="#" class='nav__item-link' tabindex="8">
      <span> &lArr; </span>
    </a>
  </li>
</ul>
<div class='navigation'>
  <a  href="#" tabindex="1"><span> Navigation</span> </a>
</div>
<script>
    var refs = document.querySelectorAll('a');
    var list = document.querySelectorAll('li a');
    var nav = document.querySelector('div a');
    nav.focus();
    [].forEach.call(refs, function(it) {
        it.addEventListener('focus',  function() {
           var ti = +this.getAttribute('tabindex');
           ti = (ti + 1).toString();
           if(this != nav) nav.setAttribute('tabindex',ti );
           if(this == list[list.length - 1]) list[0].focus();
       });
    });
</script>

s24344 21.07.2018 13:37

Замучился с корректным решением, поэтому более детально опишу задачу, очень надеюсь на вашу помощь.
#app

  a.some-links link
  a.some-links link

  ul.list
    li.list__item
      a(href="#" data-nav-id="_1").list__link First

    li.list__item
      a(href="#" data-nav-id="_2").list__link Second

    li.list__item
      a(href="#" data-nav-id="_3").list__link Third

  ul.nav
    li(data-nav-id="_1").nav__item
      a(href="#").nav__link first

      .nav__popup
        ul.nav__popup-list
          li.nav__popup-item
            a(href="#").nav__popup-link first 1
          li.nav__popup-item
            a(href="#").nav__popup-link first 2

    li(data-nav-id="_2").nav__item
      a(href="#").nav__link second

      .nav__popup
        ul.nav__popup-list
          li.nav__popup-item
            a(href="#").nav__popup-link second 1

    li(data-nav-id="_3").nav__item
      a(href="#").nav__link Third

      .nav__popup
        ul.nav__popup-list
          li.nav__popup-item
            a(href="#").nav__popup-link third 1

  a(href="#").nav-pane pane

  a.some-links link
  a.some-links link


Должно работать как данном примере: http://www.kentfa.com/

При первом нажатии на tab, первый элемент a или button принимает focus, после чего в default порядке происходит смена focus, но когда focus принимает .list__link, далее при нажатии на клавишу tab, focus переходит на .nav-pane(без фокуса он скрыт). Далее мы нажимаем на enter (space), фактически это событие click, и появляется .nav__item (с соответствуещей привязкой по data атрибутам), далее мы при нажатии на tab также меняем фокус по default порядку. Когда же будет последний элемент .list__item, мы в последний раз перейдем на .nav__popup, и далее вниз по a (button). И также важно, что default навигация, смена focus, при shift + tab, также корректно работает.

рони 21.07.2018 14:59

Цитата:

Сообщение от s24344
поэтому более детально опишу задачу,

не осилил ни ваше описание, ни даже пример, не могу понять, что вы там нашли, может кто другой сможет помочь.

s24344 21.07.2018 15:22

Если сказать проще.
http://www.kentfa.com/
В этом примере при загрузке страницы мы tab доходим до меню. Далее после каждого пункта переход на панель открытия. Можно сказать не стандартный tabindex.

рони 21.07.2018 15:53

Цитата:

Сообщение от s24344
В этом примере при загрузке страницы мы tab доходим до меню.

ок понятно, вы пост №10 смотрели?

s24344 21.07.2018 18:37

Всё, разобрался, спасибо.


Часовой пояс GMT +3, время: 11:15.