是否有处理触摸设备上的 OnMouseOver javascript 事件的首选替代方案或最佳实践?我能想到的就是将所有事件转换为 OnMouseClick。不幸的是,这混淆了悬停光标触发的事件和单击光标触发的事件之间的差异。
是否有任何替代方案或解决方法,对同时使用鼠标设备和触摸设备的网页的用户体验影响较小?
是否有处理触摸设备上的 OnMouseOver javascript 事件的首选替代方案或最佳实践?
简短的回答是否定的。
特定于设备的事件与其他设备的事件没有 1:1 的映射。使用 Touch 时,没有“悬停”的正确对应词。
鼠标事件(mouseover、mouseout、mousedown、mouseup、mousemove等)特定于鼠标输入设备。键盘有 keydown、keypress 和 keyup。触摸有 touchstart、touchmove、touchend 和 touchcancel。 iPhone/iPad/等上的 Webkit 具有 Apple 特定的额外手势开始/移动/结束事件。
更高级别的通用事件,例如 focus、blur、click、submit 等可以由这些事件之一触发。例如,可以使用鼠标、触摸或键盘事件来触发 click 事件。 (顺便说一句,click是一个名称不恰当的事件,更正确的名称应该是action,但由于其鼠标历史记录,仍然称为click)。
首选(或“One Web”)方法是对无法避免的鼠标特定事件使用鼠标事件,并对其他所有事件坚持使用通用事件。
根据 WebKit 构建和用于构建它的标志,您可以在某些特殊情况下在某些触摸界面上触发一些鼠标事件,但您确实不想在此基础上构建 UI,因为唯一的这些案例存在的原因是为了让移动 Webkit 能够在市场上获得关注。
跨平台的触摸事件也不一致。如果您正在做任何移动/触摸工作,请查看 ppk 的工作以供参考,http://quirksmode.org/mobile/tableTouch.html
根据您的需求和目标用户,您可能对(至少)移动 Safari 和 Chrome 上可用的 touch JS API 感兴趣。检查 http://backtothecode.blogspot.com/2009/10/javascript-touch-and-gesture-events.html,了解快速(可能有点过时)的介绍。我并没有真正广泛地使用这些(例如,仅针对 iPhone),但我对迄今为止获得的结果非常满意。
不幸的是,我不知道触摸设备上的最佳实践或首选替代
onmouseover
,但在遇到同样的问题时,我最终开发了这个vanillaJS解决方案,其中我计算onmouseenter
和onclick
之间的毫秒数,因此能够区分桌面点击和移动点击。
在调查桌面与移动环境中的两个事件后,我发现移动触摸本身会立即触发这两个事件(均在零毫秒内),而桌面则有几十毫秒的小延迟,具体取决于用户的操作触发幸福。
;(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>
(……或者作为小提琴)
这是另一个小提琴,专门展示桌面和移动环境之间的时间差异。
我认为我成功地创建了一个良好的模拟(至少对于我想要模拟的特定事件处理程序),通过组合“touchmove”事件处理程序并使用坐标(存储在 clientX / clientY 属性中)调用 elementFromPoint() 方法事件中相关 Touch 对象的对象)(我使用了 e.touches[0])。
有关更详细的答案,请参阅我根据我自己的问题(切换复选框状态)的解决方案对该用户的特定用例(填充表格的单元格)的回答:https://stackoverflow.com/a/ 31711040/1941313.
或者,阅读我写的关于查找写入事件处理程序设计的完整报告,包括我的发现的来源,如下要点:https://gist.github.com/VehpuS/6fd5dca2ea8cd0eb0471
(我本来可以将它们发布在 stackoverflow 中,但目前我的代表太低,所以我只能提供两个链接:P)
希望这有帮助!