Странное поведение при изменении tabindex в обработчике onchange в Internet Explorer

Учитывая следующий код:

<html>
<head>
<script>
  function updateTabIndex() {
    setTimeout(function() {
      var elem = document.getElementById("id1")
      elem.setAttribute("tabIndex", 2)
      elem.setAttribute("value", "now: tabindex 2")
    }, 100)
  }
</script>
</head>
<body>
  <h1>Weird Behaviour When Changing the tabindex in onchange Handler in Internet
    Explorer</h1>
  <p><input id="id1" tabindex="-1" value="tabindex: (-1)"/></p>
  <p><select tabindex="1" size="1" onchange="updateTabIndex()" onpropertychange="updateTabIndex()">
    <option>tabindex 1 - an option</option>
    <option>tabindex 1 - another option</option>
  </select></p>
  <p><input tabIndex="3" value="tabindex 3"/></p>


  <h2>Instructions</h2>
  <ol>
    <li>Open this page in IE. To be precise, the problem is reproducible in 
    (at least):
    <ul>
      <li>IE 8, Version 8.0.6001.18702CO on Windows XP and</li>
      <li>IE 9, Version 9.0.8112.16421 on Windows 7 Professional, 64 bit</li>
    </ul>
    <li>Use the <em>mouse</em> to change the value of the select box.</li>
    <li>As you can see, the onchange handler is called and changes the tabindex
    of the first input element.</li>
    <li>If you now tab out of the select box, you can see that the tab order is
    adhered to correctly: you go from the select box to the first input element
    and then to the last element on the page.</li>
    <li>Close the page and open it again.</li>
    <li>Click on the third input element and press Shift + Tab to enter the select
    box.</li>
    <li>Use the down arrow key on the keyboard to change the selected value in the
    select box.</li>
    <li>Now tab out of the select box.</li>
    <li>As you can see, the onchange handler is called, as before (the text in 
    the first input field has changed).</li>
    <li>However, if you tab around now, you will see that the tabindex attribute
    is ignored. Instead the order of the elements in the document source is used
    as the tab order.</li>
    <li>Even if you change the select box value with the mouse now, the tab
    order remains broken. To test again, you need to close the page and open
    it again or reload it by entering the url bar and pressing enter. Hitting
    F5 will not be enough.</li>
 </ol>
 </body>
</html>

IE игнорирует измененный порядок табуляции, когда значение поля выбора (которое запускает изменение атрибута tabindex) изменяется некоторым действием клавиатуры (клавиши со стрелками), но не игнорирует изменение tabindex, когда значение поля выбора изменяется с помощью мыши (см. более подробное объяснение ожидаемого и воспринимаемого поведения в html выше).

Почему IE так себя ведет? В частности, почему поведение при использовании мыши и при использовании клавиш отличается. Это ошибка в IE? Прямо сейчас я почти уверен, что это ошибка в IE, но, конечно, есть вероятность, что я делаю что-то не так, что просто происходит, как ожидалось, в FF.

Я уже немного погуглил, но, насколько я могу судить, об этой ошибке (если она есть) до сих пор нигде не сообщалось и не обсуждалось.

Некоторые замечания

Во-первых, Firefox не демонстрирует такого странного поведения.

Чтобы не быть неправильно понятым, ясно, что, когда я выхожу из поля выбора, я перехожу к вводу с tabindex 3, потому что асинхронный код в обработчике onchange, возможно, еще не был выполнен. Но после этого (когда текст в первом вводе изменился) я ожидаю, что будет установлен новый порядок табуляции. Так себя ведет FF.

Кажется, что IE уже запускает событие onchange каждый раз, когда я использую клавишу со стрелкой вверх / вниз, а не когда я выхожу из поля выбора (как это делает FF). Я не уверен, связано ли это с проблемой.

Добавлен бонус: если вы откроете инструменты разработчика IE, вы увидите, что атрибут tabIndex установлен правильно в DOM, также при изменении значения поля выбора без мыши. Но tabindex игнорируется при переходе по табуляции.

Мое (наивное) предположение состоит в том, что IE сохраняет внутреннее представление taborder и что это внутреннее представление не пересчитывается правильно в этом случае.

Еще одна странность: вы можете удалить строки 5 и 9 этого файла (вызов setTimeout и закрывающая фигурная скобка), чтобы изменение tabindex больше не вызывалось асинхронно. Затем он будет работать правильно, если вы введете выделение с помощью мыши и оставите его, выполнив табуляцию. Он по-прежнему ломается, если вы перейдете к выбору, измените значение с помощью клавиши со стрелкой и табуляции.


person basti1302    schedule 09.07.2013    source источник
comment
Я поместил ваш код в скрипку ...   -  person Teemu    schedule 09.07.2013
comment
По какой-то причине jsfiddle.net, похоже, сейчас у меня не работает в IE 9. Зависает при инициализации офигенно !. Не так уж и круто :-)   -  person basti1302    schedule 10.07.2013
comment
Закройте DevTools при загрузке скрипки, откройте, когда она полностью загружена.   -  person Teemu    schedule 10.07.2013
comment
Я их не открывал. Кроме того, в IE 8 сайт jsfiddle кажется сломанным. В любом случае, этот вопрос не о совместимости jsfiddle с IE :-)   -  person basti1302    schedule 10.07.2013
comment
Он также сломан в IE 10 в Windows 7.   -  person basti1302    schedule 10.07.2013


Ответы (3)


В JSFiddle изменение кода для установки свойства JavaScript вместо атрибута, похоже, помогает ...

  elem.tabIndex = 2;
  // elem.setAttribute("tabIndex", 2);
person EricLaw    schedule 09.07.2013
comment
Нет, это не так. Перед тем, как опубликовать вопрос, я попробовал все очевидные альтернативы: elem.setAttribute (tabIndex, 2), elem.setAttribute (tabindex, 2), elem.tabIndex = 2, elem.tabindex = 2. Ни один из них не работает должным образом. Похоже, вам нужно выйти из поля выбора после изменения значения с помощью стрелки вниз, чтобы воспроизвести проблему. - person basti1302; 10.07.2013
comment
Я обновил вопрос, чтобы подчеркнуть, что вам нужно выйти из поля выбора, чтобы правильно воспроизвести проблему. - person basti1302; 10.07.2013
comment
Увы, странностям этого нет конца. В вашей версии это работает, если - сразу после нажатия стрелки вниз для изменения значения - поле выбора теряет фокус, например, при щелчке мышью в какой-либо пустой области страницы. Но он по-прежнему не работает, если вы выберете вкладку после нажатия стрелки вниз. Моя исходная версия (с setAttribute) ломается в обоих случаях. Таким образом, ваше изменение действительно меняет ситуацию, хотя и не решает проблему полностью. - person basti1302; 10.07.2013
comment
Да, и это также имеет значение, если вы войдете в поле выбора, нажав на него табуляцию или щелкнув по нему мышью. - person basti1302; 10.07.2013

Мой коллега нашел интересный обходной путь: просто добавьте

elem.parentNode.replaceChild(elem, elem)

после установки tabindex заставляет его работать. Похоже, эта манипуляция с DOM запускает пересчет внутреннего порядка табуляции IE, который в противном случае отсутствует.

Хотя это лучше, чем отсутствие решения, это довольно уродливый прием. :-(

Если кто-нибудь знает другое решение с меньшей грубой силой, мне все равно было бы интересно.

person basti1302    schedule 10.07.2013

Я столкнулся с аналогичной проблемой при работе со скрытыми переключателями в IE 9. Я установил для tabIndex значение -1, но вы все равно можете перейти к группе переключателей. Мое обходное решение состояло в том, чтобы изменить свойство видимости CSS, из-за которого IE игнорировал группу.

Чтобы скрыть переключатели от странного поведения табуляции в IE 9:

$radioBtns.attr('tabIndex', -1).css('visibility', 'hidden');

Чтобы отобразить переключатели и возобновить стандартное поведение табуляции:

$radioBtns.removeAttr('tabIndex').css('visibility', '');
person Web Guy Ian    schedule 17.10.2014