从触摸事件生成鼠标事件
好的,在这里看到这个问题有一段时间了,没有人提出我会给出的答案。
与鼠标事件不同,触摸事件涉及与 UI 的许多接触点。为了适应这一点,触摸事件提供了一系列接触点。由于鼠标不能同时在两个地方,因此这两种交互方法应该真正分开处理,以获得最佳的用户体验。 OP,因为您没有询问有关检测设备是触摸还是鼠标驱动的问题,所以我已将其留给其他人询问。
同时处理
鼠标和触摸事件可以共存。在没有任何一个或另一个的设备上添加鼠标或触摸事件的侦听器不是问题。缺少的输入接口根本不会生成任何事件。这使得为您的页面实施透明的解决方案变得容易。
这取决于您喜欢哪个接口,并在其硬件不可用时模拟该接口。在这种情况下,我将从创建的任何触摸事件中模拟鼠标。
以编程方式创建事件。
代码使用 MouseEvent 对象来创建和调度事件。它使用简单,事件与真实的鼠标事件没有区别。有关 MouseEvents 的详细说明,请转到 MDN MouseEvent
最基本的。
创建鼠标点击事件并将其发送到文档
var event = new MouseEvent( "click", {'view': window, 'bubbles': true,'cancelable': true});
document.dispatchEvent(event);
您还可以将事件分派给单个元素。
document.getElementById("someButton").dispatchEvent(event);
监听事件与监听鼠标是一样的。
document.getElementById("someButton").addEventListener(function(event){
// your code
));
MouseEvent 函数中的第二个参数是您可以添加有关事件的额外信息的位置。例如说clientX 和clientY 鼠标的位置,或者which 或buttons 正在按下哪个按钮。
如果你看过mouseEvent,你就会知道有很多属性。因此,您在鼠标事件中发送的确切内容将取决于您的事件侦听器正在使用什么。
触摸事件。
触摸事件类似于鼠标。有touchstart、touchmove 和touchend。它们的不同之处在于它们提供一系列位置,每个接触点一个项目。不确定最大值是多少,但对于这个答案,我们只对一个感兴趣。详情请参阅MDN touchEvent。
我们需要做的是,对于只涉及一个接触点的触摸事件,我们要在同一位置生成相应的鼠标事件。如果触摸事件返回多个接触点,我们无法知道它们的预期焦点在哪一个,所以我们将直接忽略它们。
function touchEventHandler(event){
if (event.touches.length > 1){ // Ignor multi touch events
return;
}
}
所以现在我们知道了触摸单个联系人我们可以根据触摸事件中的信息来创建鼠标事件。
最基本的
touch = event.changedTouches[0]; // get the position information
if(type === "touchmove"){
mouseEventType = "mousemove"; // get the name of the mouse event
// this touch will emulate
}else
if(type === "touchstart"){
mouseEventType = "mousedown"; // mouse event to create
}else
if(type === "touchend"){
mouseEventType = "mouseup"; // ignore mouse up if click only
}
var mouseEvent = new MouseEvent( // create event
mouseEventType, // type of event
{
'view': event.target.ownerDocument.defaultView,
'bubbles': true,
'cancelable': true,
'screenX':touch.screenX, // get the touch coords
'screenY':touch.screenY, // and add them to the
'clientX':touch.clientX, // mouse event
'clientY':touch.clientY,
});
// send it to the same target as the touch event contact point.
touch.target.dispatchEvent(mouseEvent);
现在,当用户仅在一个位置触摸设备时,您的鼠标侦听器将收到 mousedown、mousemove、mouseup 事件。
错失点击
到目前为止一切都很好,但是缺少一个鼠标事件,这也是必需的。 “onClick”我不确定是否存在等效的触摸事件,作为练习,我看到有足够的信息来决定一组触摸事件是否可以被视为一次点击。
这将取决于开始和结束触摸事件的距离,超过几个像素和它的拖动。这也取决于多长时间。 (虽然和鼠标不一样) 我发现人们倾向于点击进行点击,而鼠标可以按住,代替构象上的释放,或者拖开来取消,这不是人们使用触摸界面的方式。
所以我记录了 touchStart 事件发生的时间。 event.timeStamp 以及它开始的地方。然后在touchEnd 事件中,我找到了它移动的距离和之后的时间。如果它们都在我设置的限制范围内,我还会生成一个鼠标单击事件以及鼠标向上事件。
这就是将触摸事件转换为鼠标事件的基本方法。
一些代码
下面是一个名为 mouseTouch 的小型 API,它可以完成我刚才解释的功能。它涵盖了简单绘图应用程序所需的最基本的鼠标交互。
// _______ _
// |__ __| | |
// _ __ ___ ___ _ _ ___ ___| | ___ _ _ ___| |__
// | '_ ` _ \ / _ \| | | / __|/ _ \ |/ _ \| | | |/ __| '_ \
// | | | | | | (_) | |_| \__ \ __/ | (_) | |_| | (__| | | |
// |_| |_| |_|\___/ \__,_|___/\___|_|\___/ \__,_|\___|_| |_|
//
//
// Demonstration of a simple mouse emulation API using touch events.
// Using touch to simulate a mouse.
// Keeping it clean with touchMouse the only pubic reference.
// See Usage instructions at bottom.
var touchMouse = (function(){
"use strict";
var timeStart, touchStart, mouseTouch, listeningElement, hypot;
mouseTouch = {}; // the public object
// public properties.
mouseTouch.clickRadius = 3; // if touch start and end within 3 pixels then may be a click
mouseTouch.clickTime = 200; // if touch start and end in under this time in ms then may be a click
mouseTouch.generateClick = true; // if true simulates onClick event
// if false only generate mousedown, mousemove, and mouseup
mouseTouch.clickOnly = false; // if true on generate click events
mouseTouch.status = "Started."; // just for debugging
// ES6 new math function
// not sure the extent of support for Math.hypot so hav simple poly fill
if(typeof Math.hypot === 'function'){
hypot = Math.hypot;
}else{
hypot = function(x,y){ // Untested
return Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
};
}
// Use the new API and MouseEvent object
function triggerMouseEvemt(type,fromTouch,fromEvent){
var mouseEvent = new MouseEvent(
type,
{
'view': fromEvent.target.ownerDocument.defaultView,
'bubbles': true,
'cancelable': true,
'screenX':fromTouch.screenX,
'screenY':fromTouch.screenY,
'clientX':fromTouch.clientX,
'clientY':fromTouch.clientY,
'offsetX':fromTouch.clientX, // this is for old Chrome
'offsetY':fromTouch.clientY,
'ctrlKey':fromEvent.ctrlKey,
'altKey':fromEvent.altKey,
'shiftKey':fromEvent.shiftKey,
'metaKey':fromEvent.metaKey,
'button':0,
'buttons':1,
});
// to do.
// dispatch returns cancelled you will have to
// add code here if needed
fromTouch.target.dispatchEvent(mouseEvent);
}
// touch listener. Listens to Touch start, move and end.
// dispatches mouse events as needed. Also sends a click event
// if click falls within supplied thresholds and conditions
function emulateMouse(event) {
var type, time, touch, isClick, mouseEventType, x, y, dx, dy, dist;
event.preventDefault(); // stop any default happenings interfering
type = event.type ; // the type.
// ignore multi touch input
if (event.touches.length > 1){
if(touchStart !== undefined){ // don't leave the mouse down
triggerMouseEvent("mouseup",event.changedTouches[0],event);
}
touchStart = undefined;
return;
}
mouseEventType = "";
isClick = false; // default no click
// check for each event type I have the most numorus move event first, Good practice to always think about the efficancy for conditional coding.
if(type === "touchmove" && !mouseTouch.clickOnly){ // touchMove
touch = event.changedTouches[0];
mouseEventType = "mousemove"; // not much to do just move the mouse
}else
if(type === "touchstart"){
touch = touchStart = event.changedTouches[0]; // save the touch start for dist check
timeStart = event.timeStamp; // save the start time
mouseEventType = !mouseTouch.clickOnly?"mousedown":""; // mouse event to create
}else
if(type === "touchend"){ // end check time and distance
touch = event.changedTouches[0];
mouseEventType = !mouseTouch.clickOnly?"mouseup":""; // ignore mouse up if click only
// if click generator active
if(touchStart !== undefined && mouseTouch.generateClick){
time = event.timeStamp - timeStart; // how long since touch start
// if time is right
if(time < mouseTouch.clickTime){
// get the distance from the start touch
dx = touchStart.clientX-touch.clientX;
dy = touchStart.clientY-touch.clientY;
dist = hypot(dx,dy);
if(dist < mouseTouch.clickRadius){
isClick = true;
}
}
}
}
// send mouse basic events if any
if(mouseEventType !== ""){
// send the event
triggerMouseEvent(mouseEventType,touch,event);
}
// if a click also generates a mouse click event
if(isClick){
// generate mouse click
triggerMouseEvent("click",touch,event);
}
}
// remove events
function removeTouchEvents(){
listeningElement.removeEventListener("touchstart", emulateMouse);
listeningElement.removeEventListener("touchend", emulateMouse);
listeningElement.removeEventListener("touchmove", emulateMouse);
listeningElement = undefined;
}
// start adds listeners and makes it all happen.
// element is optional and will default to document.
// or will Listen to element.
function startTouchEvents(element){
if(listeningElement !== undefined){ // untested
// throws to stop cut and past useage of this example code.
// Overwriting the listeningElement can result in a memory leak.
// You can remove this condition block and it will work
// BUT IT IS NOT RECOGMENDED
throw new ReferanceError("touchMouse says!!!! API limits functionality to one element.");
}
if(element === undefined){
element = document;
}
listeningElement = element;
listeningElement.addEventListener("touchstart", emulateMouse);
listeningElement.addEventListener("touchend", emulateMouse);
listeningElement.addEventListener("touchmove", emulateMouse);
}
// add the start event to public object.
mouseTouch.start = startTouchEvents;
// stops event listeners and remove them from the DOM
mouseTouch.stop = removeTouchEvents;
return mouseTouch;
})();
// How to use
touchMouse.start(); // done using defaults will emulate mouse on the entier page
// For one element and only clicks
// HTML
<input value="touch click me" id="touchButton" type="button"></input>
// Script
var el = document.getElementById("touchButton");
if(el !== null){
touchMouse.clickOnly = true;
touchMouse.start(el);
}
// For drawing on a canvas
<canvas id="touchCanvas"></canvas>
// script
var el = document.getElementById("touchButton");
if(el !== null){
touchMouse.generateClick = false; // no mouse clicks please
touchMouse.start(el);
}
// For switching elements call stop then call start on the new element
// warning touchMouse retained a reference to the element you
// pass it with start. Dereferencing touchMouse will not delete it.
// Once you have called start you must call stop in order to delete it.
// API
//---------------------------------------------------------------
// To dereference call the stop method if you have called start . Then dereference touchMouse
// Example
touchMouse.stop();
touchMouse = undefined;
// Methods.
//---------------------------------------------------------------
// touchMouse.start(element); // element optional. Element is the element to attach listeners to.
// Calling start a second time without calling stop will
// throw a reference error. This is to stop memory leaks.
// YOU Have been warned...
// touchMouse.stop(); // removes listeners and dereferences any DOM objects held
//---------------------------------------------------------------
// Properties
// mouseTouch.clickRadius = 3; // Number. Default 3. If touch start and end within 3 pixels then may be a click
// mouseTouch.clickTime = 200; // Number. Default 200. If touch start and end in under this time in ms then may be a click
// mouseTouch.generateClick; // Boolean. Default true. If true simulates onClick event
// // if false only generate mousedown, mousemove, and mouseup
// mouseTouch.clickOnly; // Boolean. Default false. If true only generate click events Default false
// mouseTouch.status; // String. Just for debugging kinda pointless really.
希望对您的代码有所帮助。