Обработка событий Hover на сенсорном экране

На веб-сайте, который я разработал, используется навигационное меню, в котором отображаются подменю: hover. Исходный сайт не использовал какой-либо отзывчивый дизайн: он ориентирован только на рабочую среду. Теперь я использую методы гибкого дизайна для таргетинга мобильных устройств и планшетов, многие из которых основаны не на мыши, а на сенсорной основе.

Большая проблема, с которой я столкнулся (и, похоже, сталкивались многие другие люди), - это навигационное меню на основе зависания: оно отлично работает в среде мыши, но на сенсорных устройствах нет надежного способа запуска hover, что затрудняет использование страницы.

Цель состоит в следующем:

  • Когда меню наводится мышью, покажите подменю.
  • При щелчке по меню с помощью мыши откройте ссылку тега привязки.
  • В первый раз, когда нажимается сенсорное меню, покажите подменю.
  • Во второй раз щелчком по нажатию кнопки открывается ссылка тега привязки.
  • Легко переключайте функциональность для планшетов, к которым также подключены мышиные устройства.

Моя команда не хочет жертвовать эффектом наведения на машинах на основе мыши. Им это нравится, и вы не хотите, чтобы нажимали меню на всех устройствах. Я согласен с этим.

Посмотрев вокруг сети, я не смог найти ни одного решения для моей проблемы. Я положил несколько из них вместе и разработал то, что хорошо тестировалось на Android, получив именно ту функциональность, которую я хотел. Есть ли что-нибудь, что можно улучшить и/или вы видите какие-либо проблемы с этим подходом?

jQuery(document).ready(function() {
    var touched=false;
    jQuery(".nav").on('touchstart', 'li .has_children', function (e) {  touched=true; });
    jQuery("html").on('mousemove', function (e) { touched=false; });

    jQuery("html").on('click', updatePreviousTouched );

    jQuery(".nav").on('click', 'li .has_children', function (e) {
        updatePreviousTouched(e);
        if( touched ) { 
            if (jQuery(this).data('clicked_once')) {
                jQuery(this).data('clicked_once', false);
                return true;
            } else {
                e.preventDefault();
                jQuery(this).trigger("mouseenter"); 
                jQuery(this).data('clicked_once', true);

            }
        }
        touched=false;
    }); 

    var previous_touched;
    function updatePreviousTouched(e) {
        if( typeof previous_touched != 'undefined' && previous_touched != null && !previous_touched.is( jQuery(e.target) ) ) {
            previous_touched.data('clicked_once', false);
        }
        previous_touched=jQuery(e.target);
    }
}

Здесь jfiddle: http://jsfiddle.net/5FfCF/1/

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

Вот результаты моих тестов:

  • Windows 7 в основных 5 браузерах: работает.
  • Android-планшет в браузере по умолчанию: работает.
  • Ноутбук Windows 7 с сенсорным экраном на IE и Chrome. Сортировка работ. Машина работает на настольной версии обоих браузеров, поэтому она не запускает событие "touchstart". Где-то между сенсорным экраном и браузером что-то превращает прикосновение в события мыши. Однако, поскольку мышь является несъемной частью этого устройства, я не считаю это провалом. Я бы хотел, чтобы он работал как планшет, но пока не существует технологии.
  • iOS iPad. Это работало по желанию, прежде чем я написал вышеупомянутый javascript. Похоже, что ios делает некоторые из этих маневров наведения/щелчка для нас за кулисами. У меня есть член команды, проверяющий, не нарушил ли мой javascript функциональность iOS, я отредактирую этот пост после получения ответа.

Другие примечания:

  • Это только меню для рабочего стола и планшета. Для мобильного сайта существует другое меню, основанное на кликах. Я бы не рекомендовал использовать это решение для устройства с размером телефона.

Ответы

Ответ 1

Piddle Diddle Fiddle:)


Fiddle Embedded Demo (используйте для телефона самый простой доступ)


Прежде чем вы прочитаете эту стену текста, проверьте скрипку и убедитесь, что это то, что вы ищете. Тест на телефоне тоже (я тестировал на своем Android и не имел проблем).

Если у вас есть совершенно отдельный набор кода для мобильных телефонов, вам не о чем беспокоиться. Адаптация к событию touch и hover особенно сложна на устройствах iOS. Но я смог преодолеть это, захватив ряд событий мыши, которые были переведены на событие касания.

В вашем конкретном случае, поскольку вы хотите, чтобы это было так разное между тремя, я предложил бы запустить ранний script, чтобы получить размер экрана, и если он меньше ### px x ### px, добавьте класс под названием handheld или mobile или что-то еще до body. Теперь вам нужно назначить код захвата touch на $('.mobile .nav') и иметь отдельный фрагмент кода, назначающий событие hover для ПК.

Для планшетов вам нужно будет решить, что для вас важнее - возможность щелчка и навигации с помощью элемента корневого меню для каждого меню или только для щелчка по элементам подменю (что устранит необходимость для добавления класса .mobile в body).

Вот код, который вы можете использовать как на мобильном, так и на рабочем столе.

JQuery

jQuery(document).ready(function () {
    $('.nav').on('click mousedown mouseup touchstart touchmove', 'a.has_children', function () {
        if ( $(this).next('ul').hasClass('open') && !$(this).parents('ul').hasClass('open')) {
            $('.open').removeClass('open');
            return false;
        }
        $('.open').not($(this).parents('ul')).removeClass('open');
        $(this).next('ul').addClass('open');
        return false;
    });
    $(document).on('click', ':not(.has_children, .has_children *)', function() {        
        if( $('.open').length > 0 ) {
            $('.open').removeClass('open');
            return false;
        }
    });
});

Обычно я не копирую весь HTML-код, как я должен сделать, но в этом конкретном случае вам нужно принять его точно так же, как у меня есть здесь, чтобы избежать ошибки inline-block белого пробела. Сравните мою скрипту с вашим оригиналом и посмотрите, насколько проще навести/щелкнуть по каждой ссылке.

HTML:

<div class="header-nav-menu">
    <ul class="nav">
        <li><a href="#" onclick="location.href='http://www.google.com'; return false;">One</a></li><li>
        <a class="has_children" href="#" onclick="location.href='http://www.google.com'; return false;">Two</a>
            <ul>
                <li><a href="#" onclick="location.href='http://www.google.com'; return false;">2A</a></li><li>
                <a href="#" onclick="location.href='http://www.google.com'; return false;">2B</a>

                </li>
                <li><a href="#" onclick="location.href='http://www.google.com'; return false;">2C</a>

                </li>
            </ul>
        </li><li>
        <a class="has_children" href="#" onclick="location.href='http://www.google.com'; return false;">Three</a>
            <ul>
                <li><a href="#" onclick="location.href='http://www.google.com'; return false;">3A</a>

                </li>
                <li> <a class="has_children" href="#" onclick="location.href='http://www.google.com'; return false;">3B</a>

                    <ul>
                        <li><a href="#" onclick="location.href='http://www.google.com'; return false;">3BI</a>

                        </li>
                        <li><a href="#" onclick="location.href='http://www.google.com'; return false;">3BII</a>

                        </li>
                        <li><a href="#" onclick="location.href='http://www.google.com'; return false;">3BIII</a>

                        </li>
                    </ul>
                </li>
                <li><a href="#" onclick="location.href='http://www.google.com'; return false;">3C</a>

                </li>
            </ul>
        </li><li>
        <a href="#" onclick="location.href='http://www.google.com'; return false;">Four</a></li><li>
        <a href="#" onclick="location.href='http://www.google.com'; return false;">Five</a></li>
    </ul>
</div>

Довольно уверен, что я даже не коснулся CSS, поэтому я оставлю это в Fiddle на данный момент. Надеюсь, это поможет вам на вашем пути.