【问题标题】:How do I simulate a hover with a touch in touch enabled browsers?如何在启用触摸的浏览器中模拟悬停?
【发布时间】:2011-02-20 13:18:09
【问题描述】:

使用一些像这样的 HTML:

<p>Some Text</p>

然后是这样的一些 CSS:

p {
  color:black;
}

p:hover {
  color:red;
}

如何允许在支持触控的设备上长按来复制悬停?我可以更改标记/使用 JS 等,但想不出一个简单的方法来做到这一点。

【问题讨论】:

  • 我特别想 iPhone OS - 它是 CSS 动画的演示,对于许多人来说,使用悬停而不是点击开始很容易。

标签: javascript html css hover touch


【解决方案1】:

2019 年已解决 - 触摸时悬停

现在似乎最好避免将悬停与 ios 或触摸一起使用。只要保持触摸并且没有其他 ios 弹出窗口,以下代码就会应用您的 css。这样做;

  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 可能会以不同方式处理输入等

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 此解决方案是否允许在第二次点击时执行链接?
    • 不,它仍然会触发第一次触摸的点击。我刚刚测试过。
    • 很棒的解决方案!快速简单。
    【解决方案3】:

    好的,我已经解决了!它涉及稍微更改 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 听众(或类似的),但我想知道是否有更好的方法。谢谢!
    • 是否可以忽略滚动手势?这正是我需要的,但现在我无法上下滚动具有这种效果的内容。
    • 我删除了 preventDefault 因为我希望滚动可用,但感谢有关 touchstart 和 touchend 的提示!上帝发送这是唯一可靠地适用于所有浏览器的答案。
    【解决方案4】:

    我个人的喜好是将: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();
        }
    });
    

    【讨论】:

      【解决方案5】:

      添加此代码,然后将类“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>

      【讨论】:

        【解决方案6】:

        试试这个:

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

        【讨论】:

        • 这对我有用.. 其他一些可能更有助于此的事情不是添加 javascript,而是这样做: 然后在 css :active 事件中添加一个小计时器: tr:active { 背景色:#118aab;过渡:所有 .2s 线性; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit 用户选择:无; -webkit-touch-callout: 无 }
        • 为我工作。谢谢...唯一的 - 它有点滞后......我的意思是 - 在你按下后,它不会立即加载。
        • 使用 fastclick.js 消除滞后
        【解决方案7】:

        进一步改进的解决方案

        首先我采用了 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');
        });
        

        但是,当出现选项菜单时,它不再触发'porthend'负责切换课程,然后下次鼠标行为将是另一个方式,完全混合。

        然后,一个解决方案将再次有条件地找出我们所处的事件,或者只是做单独的事件,并使用 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解决方案

        现在,第二次,更清洁、更整洁且响应迅速,只需使用 javascript(.hover 类和伪 :hover 之间没有混合),您可以从那里直接调用您的 ajax 行为通用(移动和桌面)'click' 事件,我找到了a pretty well answered question,从中我终于明白了如何将触摸和鼠标事件混合在一起,而不需要几个事件回调不可避免地改变彼此的事件事件链。方法如下:

        $('.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!
            }
        });
        

        【讨论】:

          【解决方案8】:

          鼠标hover效果无法在触控设备上实现。当我在 safari ios 出现同样的情况时,我在 css 中使用了 :active 来生效。

          即。

          p:active {
            color:red;
          }
          

          在我的情况下它的工作。也许这也是可以在不使用 javascript 的情况下使用的情况。试试看吧。

          【讨论】:

            【解决方案9】:

            使用也可以使用 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;}
            

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

            【讨论】:

              【解决方案10】:

              我找到的最简单的解决方案:我有一些带有 :hover css 规则的 标签。我切换到 和瞧。 iOS 中的悬停样式开始起作用。

              【讨论】:

                【解决方案11】:

                原生 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' );
                     });
                   }
                

                【讨论】:

                • 抱歉学究但jquery是javacript
                • @matpol:jQuery 是 javascript,但 javascript 不是 jQuery。特别为你我添加了“纯”这个词,纯javascript。先生满意吗?
                • 如果不使用“纯”javascript,就无法使用 jquery。我之所以这么说,是因为一些经常使用 SO 的人似乎并不知道这一点。
                • 原生 Javascript 和 jQuery 的混合,满意吗?
                【解决方案12】:

                回答您的主要问题:“如何在支持触摸的浏览器中模拟悬停?”

                只需允许“点击”元素(通过点击屏幕),然后使用 JavaScript 触发 hover 事件。

                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/

                如果您想使用“长触摸”来触发悬停,可以使用上面的代码 sn-p 作为起点,并享受计时器和其他东西的乐趣;)

                【讨论】:

                • 我不知道那个 onhover.call(p) 位,这很酷。虽然没有悬停...
                • 你用多个元素和长触摸测试过这个吗?这意味着用户在屏幕上移动手指,并为每个元素显示悬停样式?
                • 好像如果你已经在使用 jQuery,你也许可以用 jQuery 本身调用悬停事件,例如:jQuery.hover();不过,不确定 api 是否支持。
                • 哎呀,这个评论更适用于上面实际使用 jQuery 的帖子,对不起。
                • 是否需要特殊的脚本或调用函数?它对我有用,但只在一页上,我不知道有什么区别。
                【解决方案13】:

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

                这是 Apple 对touch handling 的总体评价,因为您提到了 iPhone。

                【讨论】:

                • 链接内容现在还相关吗?
                【解决方案14】:

                如果没有设备(或者更确切地说是浏览器)特定的 JS,我很确定你不走运。

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-06-22
                  • 2012-02-16
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-08-08
                  • 1970-01-01
                  • 2014-05-17
                  • 2012-02-17
                  相关资源
                  最近更新 更多