如何在启用触摸的浏览器中通过触摸模拟悬停?


120

使用这样的HTML:

<p>Some Text</p>

然后像这样的一些CSS:

p {
  color:black;
}

p:hover {
  color:red;
}

如何允许在启用触摸的设备上进行长时间触摸来复制悬停?我可以更改标记/使用JS等,但是想不出一种简单的方法来做到这一点。


我特别想到的是iPhone OS-它是CSS动画的演示,在该演示中,对于许多人来说,使用悬停而不是单击即可轻松启动。
Rich Bradshaw 2010年

Answers:


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如果用户触摸一个元素并拖动到另一个元素(例如,如果他们触摸了错误的项目并试图取消触摸)
将会使事情变得混乱

我删除了它,touchendpreventDefault()在我的网站上运行良好,但是现在菜单无法通过轻按目标而自动关闭。
ДаниилПронин

我还希望获得一些有关在用户触摸其他地方或开始滚动时如何关闭此类菜单的建议。我想touchstart身体上可能还有另一个听众(或类似的听众),但我想知道是否有更好的方法。谢谢!
Darryl Young

2
反正有没有忽略滚动手势?这正是我需要的功能,但是现在我无法上下滚动具有此效果的内容。
Alsobubbly

1
我删除了preventDefault,因为我希望滚动条可用,但是感谢touchstart和touchend的提示!上帝发送的这是在所有浏览器中都能可靠运行的唯一答案。
Petraeus

54

您需要做的就是在父级上绑定touchstart。这样的事情会起作用:

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

您无需在函数中执行任何操作,将其留空。这足以使鼠标悬停,因此触摸的行为更像:hover而不太像:active。iOS魔术。


2
此解决方案是否允许在第二次点击时执行链接?
samuelkobe 2015年

1
不,它仍会触发第一次触摸的点击。我刚刚测试过。
杰克

很棒的解决方案!快捷方便。
Hunter Turner

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事件中添加一个小的计时器:tr:active {background-color :#118aab; 过渡:所有.2s线性;-webkit-tap-highlight-color:rgba(0,0,0,0); -webkit-user-select:无;-webkit-touch-callout:none}
Kozy

为我工作。谢谢...唯一的事情-有点滞后...我的意思是-按下后,它不会立即加载。
罗曼·洛舍夫

使用fastclick.js消除时滞
Anselm

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)有点酷。虽然没有悬停...
Rich Bradshaw 2010年

您是否已通过多种要素和长距离接触对它进行了测试?意味着用户在屏幕上移动手指,并为每个元素显示悬停样式?
马库斯(Marcus)

好像您已经在使用jQuery一样,您也许可以使用jQuery本身来调用hover事件,例如:jQuery.hover(); 不过,不确定该API是否支持。
2011年

抱歉,该评论更适用于以上实际使用jQuery的帖子。
卡扎伊2011年

您是否需要任何特殊的脚本或调用函数?它对我有用,但只有一页,我不知道有什么区别。
理查德·杨

13

进一步改进的解决方案

首先,我采用了Rich Bradshaw的方法,但是随后出现了问题。通过在“ touchstart”事件上执行e.preventDefault(),页面将不再滚动,长按也无法触发选项菜单,双击缩放也无法完成执行。

一个解决方案可能是找出正在调用哪个事件,而仅在后面的事件“ touchend”中找到e.preventDefault()。由于滚动的'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');
});

但是,当出现选项菜单时,它将不再触发负责切换课程的“触摸端”,而下一次悬停行为将完全相反。

然后,解决方案将是,有条件地找出我们处于哪个事件中,或者只是单独进行一个事件,然后分别在'touchstart''touchend'上使用addClass()removeClass (),以确保该事件始终以分别添加和删除,而不是有条件地决定。最后,我们还将绑定移除回调与'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类和pseudo:hover之间没有混合),并且您可以从那里直接调用通用(移动和桌面)“ click”事件的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我使用:active在css中使用了效果。

即。

p:active {
  color:red;
}

就我而言,它的工作原理。可能也是这种情况,无需使用javascript就可以使用。试一试。


2

添加此代码,然后将类“ tapHover”设置为您要以此方式工作的元素。第一次点击元素时,它将获得伪类“:hover”和类“ tapped”。点击事件将被阻止。第二次单击同一元素-将触发click事件。

// 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,我很确定您不走运。

编辑:以为您想避免这种情况,直到我重新阅读您的问题。对于Mobile Safari,您可以注册以获取所有触摸事件,类似于使用本机UIView-s可以进行的操作。目前找不到文档,请尝试尝试。


1

一种方法是在触摸开始时执行悬停效果,然后在触摸移动或结束时删除悬停效果。

自从您提到iPhone以来,这就是Apple 通常在触摸处理方面要说的话。


链接内容现在仍然有用吗?
Flavien Volken '17

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一起使用,或者通常避免触摸。下面的代码只要保持触摸就适用您的CSS,并且没有其他ios弹出按钮。做这个;

  1. jQuery添加:$(“ p”)。on(“ touchstart”,function(e){$(this).focus(); e.preventDefault();});

  2. CSS:将p:hover替换为p:focus,然后添加p:active

选项;

  • 用任何类替换jquery p选择器

  • 要保持效果,请同时保持p:hover并添加body {cursor:ponter;},以便在任意位置轻按即可结束

  • 尝试单击和鼠标悬停事件以及同一代码中的touchstart(但未经测试)

  • 删除e.preventDefault(); 使用户能够利用ios弹出按钮,例如复制

笔记

  • 仅针对文本元素进行测试,ios可能会以不同方式对待输入等

  • 仅在使用Safari或Chrome的iphone XR ios 12.1.12和ipad 3 ios 9.3.5上进行了测试。


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
matpol

2
@matpol:jQuery是javascript,但javascript不是jQuery。为您特别,我添加了单词“ pure”(纯javascript)。先生满意吗?
Codebeat 2013年

如果不使用“纯” javascript,就无法使用jquery。我之所以指出这一点是因为一些经常这样做的人似乎并不了解这一点。
matpol

5
满足于本机Javascript和jQuery的混合?
Codebeat 2013年

0

我找到的最简单的解决方案:我有一些<span>标签,其中包含:hover css规则。我换了<a href =“ javascript:void(0)”>和voilà。iOS中的悬停样式开始起作用。


0

使用也可以使用CSS,将焦点和活动对象(适用于IE7及以下版本)添加到隐藏链接。带有类菜单的div中的ul菜单示例:

.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;}

已经晚了并且未经测试,应该可以工作;-)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.