OnMouseOver 触控的首选替代方案

Posted

技术标签:

【中文标题】OnMouseOver 触控的首选替代方案【英文标题】:Preferred Alternative to OnMouseOver for touch 【发布时间】:2010-12-28 23:45:52 【问题描述】:

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

是否有任何替代方案或变通方案,对将与鼠标设备和触摸设备一起使用的网页的用户体验破坏性较小?

【问题讨论】:

【参考方案1】:

是否有在触摸设备上处理 OnMouseOver javascript 事件的首选替代方案或最佳实践?

简短的回答是否定的。

特定于设备的事件与来自其他设备的事件没有 1:1 的映射关系。使用触控时没有适当的“悬停”等价物。

鼠标事件(mouseovermouseoutmousedownmouseupmousemove等)特定于鼠标输入设备。键盘有 keydownkeypresskeyup。触摸有 touchstarttouchmovetouchendtouchcancel。 iPhone/iPad/etc 上的 Webkit 具有 Apple 特定的其他 手势开始/移动/结束事件。

focusblurclicksubmit等更高级的通用事件由这些事件之一触发。例如,click 事件可以使用鼠标、触摸或键盘事件触发。 (click,顺便说一句,是一个名称不合适的事件,应该更恰当地称为 action,但由于它的鼠标历史仍然称为 click)。

首选(或“一个 Web”)方法是将鼠标事件用于您无法避免的鼠标特定事件,并坚持使用通用事件处理其他所有事件。

根据 WebKit 构建和用于构建它的标志,您可以在 一些特殊情况下一些触摸界面上触发 一些鼠标事件 ,但您真的不想在此基础上构建您的 UI,因为这些案例存在的唯一原因是为了让移动 Webkit 在市场上获得吸引力。

触摸事件在不同平台之间也不一致。如果你在做任何移动/触控的事情,看看 ppk 的工作以获取一些参考,http://quirksmode.org/mobile/tableTouch.html

【讨论】:

【参考方案2】:

onmouseover/onmouseout javascript 事件将转换为 touchenter/touchleave 触摸事件,问题是这些事件刚刚开始在浏览器中实现(它们是 W3C draft 的一部分),目前只有 firefox support it,因此,如果您使用的是 webkit,则必须等待它,或者使用 touchmove 事件实现 onmouseover 功能并查看坐标并查看它们是否与您的 html 元素的坐标重叠。

【讨论】:

【参考方案3】:

根据您的需求和目标用户,您可能对(至少)在移动 Safari 和 Chrome 上可用的触摸 JS API 感兴趣。检查http://backtothecode.blogspot.com/2009/10/javascript-touch-and-gesture-events.html,快速(可能有点过时)介绍。我并没有真正广泛地使用这些(例如,仅针对 iPhone),但我对目前所获得的结果感到非常满意。

【讨论】:

【参考方案4】:

不幸的是,我不知道触摸设备上@9​​87654323@ 的最佳实践或首选替代方案,但在遇到同样的问题时,我最终开发了这个 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)

这里是another fiddle,专门展示桌面和移动环境之间的时间差异。

【讨论】:

运行良好,在 Chrome 最新版本 9-30-2020 上也在 Brave 浏览器中进行了测试。谢谢【参考方案5】:

我想我设法通过组合“touchmove”事件处理程序并使用坐标调用 elementFromPoint() 方法(存储在 clientX / clientY事件中相关 Touch 对象的属性(我使用了 e.touches[0])。

如需更详细的答案,请参阅我根据我自己的问题(切换复选框状态)的解决方案在此处针对此用户的特定用例(填充表格的单元格)的答案:https://***.com/a/31711040/1941313。

或者,阅读我写的关于查找写事件处理程序设计的完整报告,包括我在以下要点中的发现的来源:https://gist.github.com/VehpuS/6fd5dca2ea8cd0eb0471

(我会在***中发布它们,但我的代表目前太低,所以我只能提供两个链接:P)

希望这会有所帮助!

【讨论】:

以上是关于OnMouseOver 触控的首选替代方案的主要内容,如果未能解决你的问题,请参考以下文章

DOS事件

多点触控 地图缩放

多点触控与多鼠标支持

js触摸事件详细解读

JS移动端获取触控位置

mini2440 P35 : 告别一线触控,还原四线触控