Как имитировать зависание с помощью сенсорных браузеров? - PullRequest
117 голосов
/ 17 мая 2010

С некоторыми HTML, как это:

<p>Some Text</p>

Тогда немного CSS вроде этого:

p {
  color:black;
}

p:hover {
  color:red;
}

Как разрешить длительное касание на сенсорном устройстве для репликации наведения? Я могу изменить разметку / использовать JS и т. Д., Но не могу придумать простой способ сделать это.

Ответы [ 14 ]

170 голосов
/ 23 мая 2010

ОК, я решил это! Это предполагает незначительное изменение CSS и добавление JS.

Использование jQuery для простоты:

$(document).ready(function() {
    $('.hover').on('touchstart touchend', function(e) {
        e.preventDefault();
        $(this).toggleClass('hover_effect');
    });
});

На английском языке: когда вы начинаете или заканчиваете касание, включите или выключите класс hover_effect.

Затем в своем HTML добавьте наведение класса ко всему, с чем вы хотите, чтобы это работало. В вашем CSS замените любой экземпляр:

element:hover {
    rule:properties;
}

с

element:hover, element.hover_effect {
    rule:properties;
}

И просто для большей полезности, добавьте это и в свой CSS:

.hover {
-webkit-user-select: none;
-webkit-touch-callout: none;        
}

Чтобы остановить браузер с просьбой скопировать / сохранить / выбрать изображение или что-то еще.

Легко!

51 голосов
/ 11 апреля 2014

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

$('body').on('touchstart', function() {});

Вам не нужно ничего делать в функции, оставьте ее пустой. Этого будет достаточно для того, чтобы навести курсор на прикосновение, поэтому прикосновение ведет себя как: hover и менее похоже: active iOS magic.

40 голосов
/ 23 июня 2013

Попробуйте это:

<script>
document.addEventListener("touchstart", function(){}, true);
</script>

И в вашем CSS:

element:hover, element:active {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
-webkit-touch-callout: none /*only to disable context menu on long press*/
}

С этим кодом вам не нужен дополнительный класс .hover!

24 голосов
/ 17 мая 2010

Чтобы ответить на ваш главный вопрос: «Как имитировать зависание в браузерах с поддержкой касания?»

Просто разрешите «щелкать» по элементу (касанием экрана), а затем инициируйте событие hover, используя JavaScript.

var p = document.getElementsByTagName('p')[0];
p.onclick = function() {
 // Trigger the `hover` event on the paragraph
 p.onhover.call(p);
};

Это должно работать, если на вашем устройстве есть событие hover (даже если оно обычно не используется).

Обновление: Я только что проверил эту технику на своем iPhone, и она, кажется, работает нормально. Попробуйте это здесь: http://jsfiddle.net/mathias/YS7ft/show/light/

Если вы хотите использовать «длинное касание» для запуска наведения, вы можете использовать приведенный выше фрагмент кода в качестве отправной точки и получать удовольствие от таймеров и прочего;)

13 голосов
/ 24 сентября 2015

Дальнейшее улучшенное решение

Сначала я выбрал подход Рича Брэдшоу , но затем начали появляться проблемы. Выполняя событие e.preventDefault () для 'touchstart' , страница больше не прокручивается и ни длительное нажатие не может вызвать меню параметров, ни увеличение двойным щелчком не может закончить выполнение.

Решением может быть выяснение, какое событие вызывается, и просто e.preventDefault () в последующем, 'touchend' . Поскольку прокрутка 'touchmove' предшествует 'touchend' , она остается по умолчанию, и 'click' также запрещается, поскольку она идет после слов в примененной цепочке событий на мобильный, вот так:

// Binding to the '.static_parent' ensuring dynamic ajaxified content
$('.static_parent').on('touchstart touchend', '.link', function (e) {

    // If event is 'touchend' then...
    if (e.type == 'touchend') {
        // Ensuring we event prevent default in all major browsers
        e.preventDefault ? e.preventDefault() : e.returnValue = false;
    }

    // Add class responsible for :hover effect
    $(this).toggleClass('hover_effect');
});

Но затем, когда появляется меню опций, оно больше не вызывает 'touchend' , отвечающее за отключение класса, и в следующий раз поведение при наведении будет наоборот, полностью перепутано.

Тогда решением, опять же, будет условное определение того, в каком событии мы находимся, или просто выполнение отдельных событий, и использование addClass () и removeClass () соответственно на 'touchstart' и 'touchend' , гарантируя, что он всегда начинается и заканчивается, соответственно добавляя и удаляя вместо условного выбора. Для завершения мы также свяжем обратный вызов удаления с типом события 'focusout' , оставаясь ответственными за очистку класса наведения любой ссылки, который может оставаться и никогда не повторяться, например:

$('.static_parent').on('touchstart', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('touchend focusout', '.link', function (e) {
    // Think double click zoom still fails here
    e.preventDefault ? e.preventDefault() : e.returnValue = false;
    $(this).removeClass('hover_effect');
});

Внимание: Некоторые ошибки все еще встречаются в двух предыдущих решениях, и, также подумайте (не проверено), двойное нажатие по-прежнему не работает.

Опрятное и, надеюсь, исправление ошибок (не :)) Javascript Solution

Теперь для второго, более чистого, аккуратного и отзывчивого подхода, использующего только javascript (без сочетания классов .hover и pseudo: hover) и откуда вы можете напрямую вызывать поведение ajax в универсальном (мобильное и настольное) событие «click» , я нашел довольно хорошо отвеченный вопрос , из которого я наконец понял, как можно смешивать события касания и мыши вместе без нескольких обратных вызовов событий неизбежно меняя друг друга по цепочке событий. Вот как это сделать:

$('.static_parent').on('touchstart mouseenter', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('mouseleave touchmove click', '.link', function (e) {
    $(this).removeClass('hover_effect');

    // As it's the chain's last event we only prevent it from making HTTP request
    if (e.type == 'click') {
        e.preventDefault ? e.preventDefault() : e.returnValue = false;

        // Ajax behavior here!
    }
});
3 голосов
/ 11 марта 2015

Эффект мыши hover не может быть реализован в сенсорном устройстве. Когда я оказался в такой же ситуации в safari ios, я использовал :active в css для создания эффекта.

е.

p:active {
  color:red;
}

В моем случае это работает. Может быть, это также тот случай, который может быть использован без использования JavaScript. Просто попробуйте.

2 голосов
/ 07 сентября 2016

Добавьте этот код и затем установите класс "tapHover" для элементов, которые вы хотели бы работать таким образом. При первом нажатии на элемент он получит псевдокласс «hover» и класс «tapped». Событие клика будет предотвращено. Второй раз, когда вы нажмете на тот же элемент - событие клика будет запущено.

// Activate only in devices with touch screen
if('ontouchstart' in window)
{
    // this will make touch event add hover pseudoclass
    document.addEventListener('touchstart', function(e) {}, true);

    // modify click event
    document.addEventListener('click', function(e) {
        // get .tapHover element under cursor
        var el = jQuery(e.target).hasClass('tapHover')
            ? jQuery(e.target)
            : jQuery(e.target).closest('.tapHover');

        if(!el.length)
            return;

        // remove tapped class from old ones
        jQuery('.tapHover.tapped').each(function() {
            if(this != el.get(0))
                jQuery(this).removeClass('tapped');
        });

        if(!el.hasClass('tapped'))
        {
            // this is the first tap
            el.addClass('tapped');
            e.preventDefault();
            return false;
        }
        else
        {
            // second tap
            return true;
        }
    }, true);
}
.box {
	float:		left;
	
	display:	inline-block;
	margin:		50px 0 0 50px;
	width:		100px;
	height:		100px;
	overflow:	hidden;
	
	font-size:	20px;
	
	border:		solid 1px black;
}
.box.tapHover {
	background:	yellow;
}
.box.tapped {
	border:		solid 3px red;
}
.box:hover {
	background:	red;
}
<div class="box" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
1 голос
/ 07 апреля 2017

Мой личный вкус - приписывать стили :hover состоянию :focus, например:

p {
    color: red;
}

p:hover, p:focus {
    color: blue;
}

Затем со следующим HTML:

<p id="some-p-tag" tabindex="-1">WOOOO</p>

И следующий JavaScript:

$("#some-p-tag").on("touchstart", function(e){
    e.preventDefault();
    var $elem = $(this);

    if($elem.is(":focus")) {
        //this can be registered as a "click" on a mobile device, as it's a double tap
        $elem.blur()
    }
    else {
        $elem.focus();
    }
});
1 голос
/ 17 мая 2010

Один из способов сделать это - сделать эффект наведения при начале касания, а затем убрать эффект наведения при перемещении или завершении касания.

Это то, что Apple должна сказать о сенсорной обработке в целом, поскольку вы упоминаете iPhone.

1 голос
/ 17 мая 2010

Без JS устройства (или, скорее, браузера), я уверен, вам не повезло.

Редактировать: думал, что ты хотел избежать этого, пока я не перечитал твой вопрос. В случае Mobile Safari вы можете зарегистрироваться, чтобы получать все сенсорные события, аналогичные тем, которые вы можете делать с нативными UIView-s. Пока не могу найти документацию, но попробую.

...