JS ArrowDown addEventListener для нескольких элементов в цикле (демо) - PullRequest
7 голосов
/ 30 января 2012

Имеет следующий слушатель для события клавиатуры ArrowDown (код клавиши 40):

window.onload = function() {    
var itemsContainer = document.getElementById('cities-drop');
document.addEventListener('keyup',function(event){
if (event.keyCode == 40 && itemsContainer.style.display=='block') {
event.preventDefault();
    for (var i=0;i<itemsContainer.children.length-1;i++){
        if (itemsContainer.getAttribute('class').substr('hovered')!=-1){
            itemsContainer.children[i].setAttribute('class','');
            itemsContainer.children[i].nextSibling.setAttribute('class','hovered');
                //break;
                }
            }
        }
    });

, в этом случае hovering переходит к последнему элементу в списке после нажатия ArrowDown.

В случае, если break не прокомментирован, он переходит ко второму элементу и больше не прыгает.

Не могу понять принцип, как это сделать, этот слушатель всегда слушает ...

РЕДАКТИРОВАТЬ живое демо
возможно, это вопрос закрытия, но я не уверен

Ответы [ 3 ]

4 голосов
/ 01 февраля 2012

После просмотра вашего кода и понимания того, что вы пытаетесь сделать, я думаю, что ваша ошибка использует substr там, где вы должны использовать indexOf. Вот обновленная строка:

if (itemsContainer.getAttribute('class').indexOf('hovered') != -1)


<час /> Подробнее: На самом деле вы использовали substr со строковым значением для индекса start. Не уверен, каков будет результат этого, но, по-видимому, это не -1, поскольку условное выражение возвращало true каждый раз, вызывая наведение следующего элемента на КАЖДЫЙ раз, вплоть до самого конца списка. Имея оператор break, он выполнял оператор if в первом элементе (вызывая «зависание» второго элемента), а затем завершал работу.

Я бы оставил там оператор break после исправления вашего кода, чтобы цикл останавливался после того, как он нашел свое совпадение, и не перебирал остальные элементы без необходимости.

<ч /> EDIT:

Я обнаружил еще пару проблем в вашем коде. Вот пример, который работает для меня в IE и FF, по крайней мере (не тестировал в Safari, Opera или Chrome):

<html>
<head>
    <style type="text/css">
        .hovered
        {
            color:red;
        }
    </style>
    <script type="text/JavaScript">
        function move(event)
        {
            var itemsContainer = document.getElementById('cities-drop');
            if (event.keyCode == 40 && itemsContainer.style.display == 'block')
            {
                if (event.preventDefault)
                    event.preventDefault();
                if (event.cancelBubble)
                    event.cancelBubble();
                if (event.stopImmediatePropagation)
                    event.stopImmediatePropagation();

                for (var i=0; i<itemsContainer.children.length-1; i++)
                {
                    if (itemsContainer.children[i].className.indexOf('hovered') != -1)
                    {
                        itemsContainer.children[i].className = "";
                        itemsContainer.children[i+1].className = "hovered";
                        break;
                    }
                }
            }
        };
    </script>
</head>
<body onkeydown="move(event)">
    <div id="cities-drop" style="display:block;">
        <p class="hovered">Item 1</p>
        <p>Item 2</p>
        <p>Item 3</p>
        <p>Item 4</p>
        <p>Item 5</p>
        <p>Item 6</p>
        <p>Item 7</p>
    </div>
</body>
</html>

<ч /> Detail: Для меня в IE9 эта функция никогда не вызывалась. Вместо этого я просто сделал ее обычной функцией и добавила событие onkeydown в тег body.

Далее, для кросс-браузерной совместимости, вы должны убедиться, что event.preventDefault существует перед его использованием. Я получил ошибку JS в IE.

В вашем операторе if было itemsContainer.getAttribute('class'). Во-первых, вам нужно было использовать itemsContainer.children[i]. Во-вторых, .getAttribute('class') не работал для меня в IE, поэтому я переключил его на .className.

Наконец, itemsContainer.children[i].nextSibling у меня не сработало, но достаточно просто изменить его на itemsContainer.children[i+1], чтобы получить следующего брата.

3 голосов
/ 02 февраля 2012

Вы можете попробовать более простой подход вместо использования цикла:

window.onload = function() {    
    var itemsContainer = document.getElementById('cities-drop');

    document.addEventListener('keyup',function(event) {
        if (event.keyCode == 40 && itemsContainer.style.display=='block') {
            event.preventDefault();

            var previousHoveredChoice = itemsContainer.querySelector('.hovered');
            previousHoveredChoice.className = '';

            var currentHoveredChoice = previousHoveredChoice.nextSibling;
            if (currentHoveredChoice) {
                currentHoveredChoice.className = 'hovered';
            }
        }
    });

    //following code is copy-pasted from the live example 
    //just to close the onload function handler in this solution
    document.addEventListener('keyup',function(event){
        if (event.keyCode == 27) {

            if (document.getElementById('cities-drop').style.display=='block'){
                document.getElementById('cities-drop').style.display='none';
            }
        }

    });
    //end of copy-pasted code
};
3 голосов
/ 01 февраля 2012

Я вижу несколько вещей, которые могут быть проблемой.Прежде всего, вы обновляете itemsContainer.children[i].nextSibling, то есть itemsContainer.children[i+1].Вот почему всегда последний элемент, который он выбрал, если вы пропустите разрыв.itemsComtainer [i + 1] всегда будет зависать, если есть элемент, соответствующий классу.

Вторая проблема - это то, на что указывает Travesty3 в своем ответе.

Я также изменил условие if напроверьте, находится ли класс hovered на одном из дочерних элементов, а не на самом контейнере.

if (itemsContainer.children[i].getAttribute('class').match('hovered'))

Я изменил обработчик событий с помощью следующих строк кода, и это, кажется, работает нормально:

document.addEventListener('keyup',function(event){
            if (event.keyCode === 40 && itemsContainer.style.display==='block') {
                event.preventDefault();
                for (var i=0,l=itemsContainer.children.length;i<l;++i){
                    if (itemsContainer.children[i].getAttribute('class').match('hovered')){
                        itemsContainer.children[i].setAttribute('class','');
                        itemsContainer.children[i+1].setAttribute('class','hovered');
                        break;
                    }
                }
            }
        });

Имейте в виду, что создание такого выпадающего элемента управления - большая работа.Пользователь ожидает навигации по нему с помощью клавиатуры.Чтобы обеспечить удобство работы с пользователем, вам необходимо использовать несколько клавиш, например клавиши со стрелками, вкладку для фокусировки элемента управления, пробел для его открытия и закрытия, буквенно-цифровой ввод для фокусировки на первом сопоставленном элементе и т. Д.

Если важно взаимодействие с пользователем, я бы порекомендовал использовать для этого фреймворк и плагин.Я лично предпочитаю JQuery и JQuery UI, и есть несколько плагинов для выбора выпадающих.Другое преимущество состоит в том, что если клиент отключил JavaScript, или ваш JavaScript по какой-либо причине ошибся, большинство плагинов используют обычный элемент выбора select, который по-прежнему будет работать нормально.

Я использовал этот плагиндля ящика select для простого раскрывающегося списка: http://www.abeautifulsite.net/blog/2011/01/jquery-selectbox-plugin/

Редактировать: Я отменяю эту рекомендацию, поскольку она не работает, если несколько элементов имеют одно и то же имя.Если это важно, вы должны проверить вместо этого плагин selectmenu группы Filament Group: http://filamentgroup.com/lab/jquery_ui_selectmenu_an_aria_accessible_plugin_for_styling_a_html_select/ // Edit

... и плагин автозаполнения jquery для комбинированного списка, также поддерживающегописьменный ввод: http://jqueryui.com/demos/autocomplete/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...