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


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.