Як я змоделюю наведення курсору на дотик у веб-переглядачах із дотиком?


120

З таким HTML, як це:

<p>Some Text</p>

Тоді такі CSS:

p {
  color:black;
}

p:hover {
  color:red;
}

Як я можу дозволити довгого торкання пристрою, що підтримує дотик, для копіювання наведення курсора? Я можу змінити розмітку / використовувати JS тощо, але не можу придумати простий спосіб зробити це.


Я конкретно думаю про iPhone OS - це демонстрація анімації CSS, на якій для багатьох легко використовувати наведення курсору, а не клацання.
— Багатий Бредшоу

Відповіді:


172

Гаразд, я це розробив! Це передбачає незначну зміну 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;        
}

Щоб зупинити браузер з проханням скопіювати / зберегти / вибрати зображення або будь-що інше.

Легко!


Це чудово. Я розділив функцію domready, хоча тому, що зіпсує toggleречі, якщо користувач торкнеться одного елемента і перетягне на інший (наприклад, якщо він торкнувся неправильного елемента і намагається скасувати дотик)
— Jacksonkr,

Я видалив touchendі preventDefault()на своєму веб-сайті він працює добре, але тепер меню не закриваються автоматично, натискаючи на мету.
— Даніїл Пронін

Я також хотів би поради, як потім закрити таке меню, коли користувач торкається десь іншого або починає прокручувати. Я думаю, може бути інший touchstartслухач на тілі (або подібний), але я задумався, чи є кращий спосіб. Дякую!
— Дарріл Янг

2
Чи варто ігнорувати жест прокрутки? Це робить саме те, що мені потрібно, але зараз я не можу прокручувати вміст, що має такий ефект, вгору та вниз.
— такожблуд

1
Я видалив prevenDefault, оскільки хочу, щоб прокрутка була доступною, але дякую за поради щодо сенсорного запуску та дотику! Дай Бог, це єдина відповідь, яка надійно працює у всіх браузерах.
— Петрей

54

Все, що вам потрібно зробити, - зв’язати сенсорний запуск на батьків. Щось подібне спрацює:

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

Вам не потрібно нічого робити у функції, залиште це порожнім. Цього буде достатньо, щоб навести курсор на дотик, тому дотик поводиться більше як: наведіть і менше схожий на: активний. iOS магія.


2
Чи дозволяє це рішення виконувати посилання на другому торці?
— samuelkobe

1
Ні, це все ще не викликає натискання на перший дотик. Я просто тестував це.
— Джек

Дивовижне рішення! Швидко і просто.
— Мисливець Тернер

41

Спробуйте це:

<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!


1
це працює для мене .. деякі інші речі, які можуть допомогти цьому ще більше, замість того, щоб додавати JavaScript, зробіть це: <body ontouchstart = ""> потім додайте невеликий таймер у css: active event: tr: active {background-color : # 118aab; перехід: всі .2s лінійні; -webkit-tap -light-color: rgba (0,0,0,0); -webkit-user-select: немає; -webkit-touch-callout: none}
— Кози

Працювали для мене. Дякую ... Єдине - це трохи відстає ... Я маю на увазі - після натискання воно не завантажується миттєво.
— Роман Лосєв

Використовуйте fastclick.js, щоб зняти відставання
— Ансельм

25

Щоб відповісти на ваше головне питання: "Як я змоделюю наведення курсору на дотик у веб-переглядачах із дотиком?"

Просто дозвольте "клацнути" по елементу (натискаючи на екран), а потім запустити 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/

Якщо ви хочете скористатися "довгим дотиком" для запуску наведення курсора, ви можете використати описаний вище фрагмент коду як вихідну точку та розважитися таймерами та іншим матеріалом;)


Я не знав про цей біт onhover.call (p), це дуже круто. Немає жодної вивіски, коли ...
— Річ Бредшоу

Ви протестували це з декількома елементами і довгим дотиком? Значить користувач пересуває палець по екрану та показує стиль наведення кожного елемента?
— Маркус

Схоже, якщо ви вже використовуєте jQuery, можливо, ви зможете просто викликати подію наведення за допомогою самої jQuery, наприклад: jQuery.hover (); Не впевнений, що api це підтримує.
— Kzqai

На жаль, це був коментар, більш застосовний до публікації вище, що насправді використовує jQuery, вибачте.
— Kzqai

Чи потрібно мати якісь спеціальні сценарії або викликати функцію? Це працює для мене, але лише на одній сторінці, і я не знаю, в чому різниця.
— Річард Янг

13

Подальше вдосконалене рішення

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

Рішенням може бути з’ясування того, яка подія викликається, і лише e.preventDefault () у наступній, «touchchend» . Оскільки "touchmove" прокрутки надходить до "touchchend", воно залишається за замовчуванням, а також "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');
});

Але тоді, коли з'явиться меню параметрів, воно більше не спрацьовує "доторкатися", що відповідає за вимкнення класу, і наступного разу поведінка наведення буде навпаки, повністю змішана.

Рішенням тоді буде, знову ж таки, умовно з’ясувати, в якій події ми перебуваємо, або просто робимо окремі, і використовувати addClass () та deleteClass () відповідно на «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

Тепер , для другої, чистіше, охайніше і чуйних, підхід тільки з допомогою JavaScript (не змішувати між .hover класом і псевдо: зависання) і звідки можна викликати безпосередньо ваша поведінка Ajax на універсальному (мобільний і настільний) «клік» подія , Я знайшов досить добре відповів на запитання, з якого я нарешті зрозумів, як я можу поєднувати події дотику та миші разом без кількох зворотних викликів подій, що неминуче змінюють один одного в ланцюжку подій. Ось як:

$('.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

Ефект миші hoverнеможливо реалізувати на сенсорному пристрої. Коли у мене з'явилася однакова ситуація, safari iosя застосував :activecss для досягнення ефекту.

тобто.

p:active {
  color:red;
}

У моєму випадку його робота. Можливо, це теж випадок, який можна використовувати з використанням JavaScript. Просто спробуйте.


2

Додайте цей код, а потім встановіть клас "tapHover" на елементи, над якими ви хотіли б працювати. Перший раз, коли ви натиснете елемент, він отримає псевдоклас ": навести курсор" і клас "тап". Подія натискання буде запобіжена. Другий раз, коли ви натиснете той самий елемент - подія натискання буде запущена.

// 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

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

Редагувати: думав, що ви хочете цього уникнути, поки я не перечитаю ваше запитання. У випадку мобільного Safari ви можете зареєструватися, щоб отримати всі сенсорні події, схожі на те, що ви можете робити з рідними UIView. Неможливо знайти документацію зараз, хоча спробуємо.


1

Один із способів зробити це - зробити ефект наведення курсора, коли дотик почнеться, а потім видалити ефект наведення, коли дотик рухається чи закінчується.

Це те, що Apple має сказати про керування сенсорним принципом , оскільки ви згадуєте iPhone.


Чи вміст посилання все ще актуальний?
— Флавіен Волкен

1

Мій особистий смак - це також приписувати :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

Вирішено 2019 рік - Наведіть курсор на дотик

Зараз, здається, найкраще уникати використання курсору взагалі з ios або touch взагалі. Наведений нижче код застосовує ваш css, якщо підтримується дотик та без інших макетів ios. Зробити це;

  1. Jquery add: $ ("p"). On ("touchstart", функція (e) {$ (це) .фокус (); e.preventDefault ();});

  2. CSS: замініть p: наведіть курсор на p: фокус та додайте p: active

Варіанти;

  • замініть селектор jquery p будь-яким класом тощо

  • щоб ефект залишався, тримайте p: також наведіть курсор миші та додайте body {cursor: ponter;}

  • спробуйте події клацання та переведення миші, а також сенсорний запуск у тому самому коді (але не перевірено)

  • видалити e.preventDefault (); щоб користувачі могли використовувати ios-макети, наприклад копіювати

Примітки

  • Тільки тестовані на текстові елементи, ios може по-різному ставитися до входів тощо

  • тестується лише на iphone XR ios 12.1.12 та ipad 3 ios 9.3.5, використовуючи Safari або Chrome.


0

Суміш рідного Javascript та jQuery:

var gFireEvent = function (oElem,sEvent) 
{
 try {
 if( typeof sEvent == 'string' && o.isDOM( oElem ))
 {
  var b = !!(document.createEvent),
     evt = b?document.createEvent("HTMLEvents"):document.createEventObject();
  if( b )    
  {  evt.initEvent(sEvent, true, true ); 
    return !oElem.dispatchEvent(evt);
  }
  return oElem.fireEvent('on'+sEvent,evt);
 }
 } catch(e) {}
 return false;
};


// Next you can do is (bIsMob etc you have to determine yourself):

   if( <<< bIsMob || bIsTab || bisTouch >>> )
   {
     $(document).on('mousedown', function(e)
     {
       gFireEvent(e.target,'mouseover' );
     }).on('mouseup', function(e)
     {
       gFireEvent(e.target,'mouseout' );
     });
   }

1
вибачте за педантичність, але jquery є javacript
— матпол

2
@matpol: jQuery - це JavaScript, але javascript - не jQuery. Спеціально для вас я додаю слово "чистий", чистий JavaScript. Задоволений сер?
— Codebeat

ви не можете використовувати jquery без використання "чистого" JavaScript. Я зазначаю лише тому, що деякі люди, які часто частішають, здається, цього не знають.
— матпол

5
Суміш рідного Javascript та jQuery, задоволений?
— Codebeat

0

Найпростіше рішення, яке я знайшов: у мене були кілька тегів <span> з правилами наведення курсору css Я переключився на <a href = "javascript: void (0)"> і voilà. Стилі наведення в iOS почали працювати.


0

Використовуйте також можна використовувати CSS, додавати фокус та активно (для IE7 та нижче) до прихованого посилання. Приклад меню ul всередині div з меню класу:

.menu ul ul {display:none; position:absolute; left:100%; top:0; padding:0;}
.menu ul ul ul {display:none; position:absolute; top:0; left:100%;}
.menu ul ul a, .menu ul ul a:focus, .menu ul ul a:active { width:170px; padding:4px 4%; background:#e77776; color:#fff; margin-left:-15px; }
.menu ul li:hover > ul { display:block; }
.menu ul li ul li {margin:0;}

Пізно і неперевірено, повинно працювати ;-)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.