OnMouseOver触控的首选替代品

时间:2010-12-28 23:45:52

标签: javascript touch

在触控设备上处理OnMouseOver javascript事件是否有首选替代或最佳做法?我只能想到将所有事件转换为OnMouseClick。不幸的是,这会混淆悬停光标触发的事件与单击光标触发的事件之间的差异。

对于将与鼠标设备和触摸设备一起使用的网页的用户体验,是否有任何替代方案或解决方案?

5 个答案:

答案 0 :(得分:35)

  

在触控设备上处理OnMouseOver javascript事件是否有首选替代或最佳做法?

简短的回答是否定的。

特定于设备的事件与其他设备的事件没有1:1的映射关系。使用Touch时,没有适当的“悬停”。

鼠标事件(鼠标悬停 mouseout mousedown mouseup mousemove 等等)特定于鼠标输入设备。键盘具有 keydown keypress keyup 。 Touch已 touchstart touchmove touchend touchcancel 。 iPhone / iPad /等上的Webkit具有Apple特有的附加手势开始/移动/结束事件。

更高级别的通用事件,例如焦点模糊点击提交等,可以是由其中一个事件触发。例如,可以使用鼠标,触摸或键盘事件触发单击事件。 (点击,顺便说一下,这是一个名称不合适的事件,应该更恰当地称为 action ,但由于其鼠标历史记录仍称为点击)。

首选(或“一个Web”)方法是将鼠标事件用于鼠标特定的事情,在这些事情中你无法避免它们,并坚持其他一切的通用事件。

根据WebKit构建和用于构建它的标志,您可以在某些特殊情况下某些触摸界面上触发一些鼠标事件 ,但你真的不想在那上构建你的UI,因为这些案例存在的唯一原因是允许mobile-Webkit在市场上获得牵引力。

触摸事件跨平台也不一致。如果您正在进行任何移动/触控操作,请查看ppk的工作作为参考,http://quirksmode.org/mobile/tableTouch.html

答案 1 :(得分:7)

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

答案 2 :(得分:4)

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

答案 3 :(得分:2)

我认为我设法通过组合“触摸移动”来创建一个好的模拟(至少对于我想要模拟的特定事件处理程序)。事件处理程序并使用事件中相关Touch对象的坐标(存储在对象的clientX / clientY属性中)调用elementFromPoint()方法(我使用了e.touches [0])。

有关更详细的答案,请根据我自己的问题解决方案(切换复选框状态)查看此用户的具体用例(填写表格的单元格)的答案:https://stackoverflow.com/a/31711040/1941313

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

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

希望这有帮助!

答案 4 :(得分:2)

不幸的是,我不知道最佳实践或触摸设备上onmouseover的{​​em>首选替代方案,但是遇到相同的问题,我最终开发了这个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专门展示了台式机和移动环境之间的时间差异。