在触屏设备上,OnMouseOver的首选替代方案是什么?

42

在触摸设备上处理OnMouseOver javascript事件有什么更好的替代方法或最佳实践吗? 我所能想到的就是将所有事件转换为OnMouseClick。不幸的是,这会混淆由悬停光标触发的事件和由单击光标触发的事件之间的差异。

有没有其他替代方案或解决方法可以减少对同时使用鼠标设备和触摸设备的网页的用户体验产生影响?

5个回答

41
是否有在触摸设备上处理OnMouseOver javascript事件的首选替代方法或最佳实践?
简短回答:没有。
设备特定事件与其他设备的事件没有1:1的映射。当使用Touch时,没有“悬停”的适当等价物。
鼠标事件(mouseover,mouseout,mousedown,mouseup,mousemove等)是特定于鼠标输入设备的。键盘具有keydown、keypress和keyup。Touch具有touchstart、touchmove、touchend和touchcancel。iPhone/iPad/等的webkit有额外的手势开始/移动/结束事件,这是苹果公司特有的。
更高级别的通用事件,如focus、blur、click、submit等,可以由其中之一的事件触发。例如,click事件可以使用鼠标、触摸或键盘事件触发。(顺便说一下,click是一个名称不合适的事件,应该更适当地称为“action”,但由于它的鼠标历史仍被称为click)。
首选(或“One Web”)方法是对于只能避免使用它们的鼠标特定事物使用鼠标事件,并对其他所有事物坚持使用通用事件。
取决于WebKit版本和用于构建它的标志,您可以在某些特殊情况下在某些触摸接口上触发一些鼠标事件,但您真的不想在此构建UI,因为存在这些情况的唯一原因是允许移动Webkit在市场上获得优势。

触摸事件在不同平台上也存在不一致性。如果你想进行任何移动/触摸相关的工作,请参考ppk的工作,http://quirksmode.org/mobile/tableTouch.html


7
在编程中,onmouseover/onmouseout javascript事件会转换为touchenter/touchleave触摸事件。问题在于这些事件刚开始在浏览器中实现(它们是W3C草案的一部分),目前只有Firefox 支持它。因此,如果您正在使用Webkit,您需要等待,或者使用touchmove事件实现您的onmouseover功能,并查看坐标是否与您的html元素的坐标重叠。

4

很不幸,我不知道在触摸设备上最佳实践或首选替代onmouseover是什么,但在遇到相同的问题时,我开发了这个vanillaJS解决方案,在onmouseenteronclick之间计算毫秒数,从而能够区分桌面点击和移动点击。

在研究桌面与移动环境中的这两个事件时,我发现移动触摸会立即触发两个事件(都在零毫秒内),而桌面需要等待几十毫秒,具体时间取决于用户的操作速度。

;(function(){
 let
  hover_on_mobile = {
   timer: 0,
      // I don't trust the timer with this,
      // so I'm counting myself:
   milliseconds: 0,
      // also cover the case of the user
      // mouseentering, reading or otherwise
      // waiting, and clicking *then*.
   is_counting: false,
  },
    item = document.querySelector('.mobile-hoverable')
 ;
 hover_on_mobile.reset = function(){
  clearInterval(hover_on_mobile.timer);
  hover_on_mobile.milliseconds = 0;
  hover_on_mobile.is_counting = false;
 };

 // hover.
 item.onmouseenter = function(){

  // preparation for onclick's touch-click detection.
  hover_on_mobile.is_counting = true;
  // count the milliseconds starting on each 
    // mouseenter anew.
  hover_on_mobile.timer = window.setInterval(function() {
   // we only need the first few milliseconds for
      // our touch-click detection.
   if (hover_on_mobile.milliseconds > 50) {
    hover_on_mobile.reset();

   } else {
    hover_on_mobile.milliseconds++;
   }
  }, 1);

  hover_behavior();
 };

 // click.
 item.onclick = function(ev){
  let
   condition1 = hover_on_mobile.milliseconds < 10,
   condition2 = hover_on_mobile.is_counting
  ;
  console.log('clicked', {
   condition1: condition1,
   condition2: condition2,
   timer: hover_on_mobile.timer,
      milliseconds: hover_on_mobile.milliseconds,
   is_counting: hover_on_mobile.is_counting,
  });
  // touch-click detection.
  if (condition1 && condition2) {
   // don't do anything; let the onmouseenter 
      // do the hover routine unhinderedly.
      //
   // if this was an onclick event on an ‹a› tag, 
      // the ev.preventDefault(); call would go here.
      
  } else {
   click_behavior();
  }
  hover_on_mobile.reset();
 };
  
  
  // ----------------------------------------
  // fiddle-specfic.

 // reset indicator, not hover_on_mobile.
 item.onmouseout = reset_indicator;

 function click_behavior() {
  document.querySelector('#indicator .click-text').innerText = 'clicked';
 }

 function hover_behavior() {
  document.querySelector('#indicator .hover-text').innerText = 'hovered';
 }

 function reset_indicator() {
  document.querySelector('#indicator .hover-text').innerText = '-';
  document.querySelector('#indicator .click-text').innerText = '-';
 }

 document.querySelector('#indicator .reset').onclick = reset_indicator;

})();
h1 {
  font-size: 20px;
  line-height: 26px;
}

#indicator {
  margin-top: 15px;
  padding: 20px;
  background-color: #ddd;
}

.mobile-hoverable {
  cursor: pointer;
  background-color: antiquewhite;
  border: 1px outset blanchedalmond;
  border-radius: 4px;
  padding: 10px;
}

.notes {
  font-style: italic;
  font-size: 14px;
}
<div class="root">
  <h1>Imagine you wanted mobile users to click once in order to simulate a desktop-hover and twice for a desktop-click</h1>
  
  <div class="mobile-hoverable">Hover me, click me, compare with mobile-touch device mode.</div>
  
  <div id="indicator">
    <button class="reset">Reset</button>
    <span class="hover-text">-</span>
    <span class="click-text">-</span>
  </div>
  
  <ul class="notes">
    <li>Don't forget to reload the page after changing the mode, for optimal testing evaluation.</li>
    <li>Click event console.logs hover_on_mobile object.</li>
    <li>The fiddle's CSS is irrelevant for this feature.</li>
    <li>Relevant JavaScript is bundled together; irrelevant JavaScript at the end.</li>
    <li>Didn't test browser compatibility specifically for this fiddle but the feature works in Chrome, Firefox, Safari, IE10+.</li>
    <li>Subsequent clicks without onmouseout will only fire the click event, in both environments.</li>
  </ul>
</div>

(… 或者作为一个fiddle的替代方案)

这里有另一个fiddle示例,专门展示了桌面和移动环境之间的时差差异。


运行良好,在Chrome最新版本9-30-2020和Brave浏览器上进行了测试。谢谢。 - Luis H Cabrejo

4

2
我认为我成功地创建了一个好的模拟(至少对于我想要模拟的特定事件处理程序),通过组合使用'touchmove'事件处理程序和调用elementFromPoint()方法,使用事件中相关Touch对象的坐标(存储在对象的clientX / clientY属性中)(我使用了e.touches [0])。
更详细的答案,请参见我针对此用户特定用例(填充表格单元格)的答案,该答案基于解决我的自身问题(切换复选框状态)的解决方案,链接如下:https://stackoverflow.com/a/31711040/1941313
或者,您可以阅读我撰写的有关查找正确事件处理程序设计的完整报告,其中包括以下gist中所述的发现来源:https://gist.github.com/VehpuS/6fd5dca2ea8cd0eb0471 (我本来会在stackoverflow上发布它们,但是我的声望目前太低,因此我只能提供两个链接:P)
希望这可以帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接