通过指针事件统一触摸和鼠标

我经常收到诸如“ 手机和平板电脑上的触控设备如此之多这样的开发人员的问题,我应该从哪里开始呢? ”和“ 触摸输入最简单的构建方法是什么? ”简短的回答: “这很复杂。”

当然,在现代的,支持触摸的浏览器中,或者作为较旧的浏览器的后备,确实存在一种更统一的方式来处理Web上的多点触摸输入。 在本文中,我想向您展示一些使用MSPointers的浏览器实验-一种新兴的多点触摸技术和polyfills,它们使跨浏览器支持变得更加复杂 。 您还可以在自己的网站上尝试并轻松使用的那种代码。

首先,网络上正在发展许多触摸技术-要获得浏览器支持,除了MSPointers之外,您还需要查看iOS触摸事件模型和W3C鼠标事件模型,以支持所有浏览器。 但是,标准化的支持(和意愿)越来越高。 九月份,Microsoft将MSPointers提交给W3C进行标准化 ,我们已经达到了最后征求意见稿: http : //www.w3.org/TR/pointereventsMS Open Tech团队最近还发布了Webkit初始Pointer Events原型

与MSPointers我之所以实验不是基于设备共享-这是因为微软的基本输入处理方法比什么是目前可在网络上完全不同,值得一看什么,它可能成为

不同之处在于,开发人员可以编写更抽象的输入形式,称为“指针”。 指针可以是鼠标光标,钢笔,手指或多指在屏幕上的任何接触点。 因此,您不会浪费时间为每种类型的输入分别编码。

概念

我们将首先回顾在Internet Explorer 10中运行的,公开了MSPointer事件API的应用程序,然后是支持所有浏览器的解决方案。 之后,我们将看到您如何利用IE10手势服务,该服务将帮助您轻松地处理JavaScript代码中的触摸。 由于Windows 8和Windows Phone 8共享相同的浏览器引擎,因此两个平台的代码和概念相同。 此外,您将在本文中接触到的所有内容都将帮助您在使用HTML5 / JS构建的Windows应用商店应用中完成相同的任务,因为这再次使用了相同的引擎。

MSPointer的思想是让您使用与您已经知道的经典鼠标事件相匹配的模式,通过单个代码库解决鼠标,笔和触摸设备的问题。 实际上,鼠标,笔和触摸具有一些共同的属性:例如,您可以与它们一起移动指针,并可以与它们一起单击元素。 然后,让我们通过同一段代码解决这些情况! 指针将聚合那些通用属性,并以类似于鼠标事件的方式公开它们。

clip_image001

然后,最明显的常见事件是: MSPointerDownMSPointerMoveMSPointerUp ,它们直接映射到等效的鼠标事件。 您将具有屏幕的X和Y坐标作为输出。

您还具有特定的事件,例如: MSPointerOverMSPointerOutMSPointerHoverMSPointerCancel

但是,当然,在某些情况下,您可能希望使用与默认鼠标行为不同的方式来解决触摸问题,以提供不同的UX。 此外,借助多点触摸屏,您可以轻松地让用户旋转,缩放或平移某些元素。 笔/手写笔甚至可以为您提供鼠标无法提供的一些压力信息。 指针事件将汇总这些差异,您将为每个设备的详细信息构建一些自定义代码。

注意:如果您在Windows 8 / RT设备上具有触摸屏(当然)或使用Windows Phone 8,则最好测试以下嵌入式示例。否则,您确实有一些选择:

1.使用免费的Visual Studio 2012 Express开发工具附带的Windows 8 Simulator获得第一级的经验。 有关其工作原理的更多详细信息,请阅读本文: 使用Windows 8 Simulator&VS 2012调试IE10触摸事件和您的响应式设计
2.观看此视频,该视频 演示了在支持触摸,笔和鼠标的Windows 8平板电脑上的以下所有示例
3.如果您无权访问Windows 8设备,请使用虚拟的跨浏览器测试服务(如BrowserStack)进行交互式测试。 您可以使用BrowserStack免费3个月时,Internet Explorer团队的礼貌modern.IE

处理简单的触摸事件

第1步:在JS中什么也不做,只添加一行CSS

让我们从基础开始。 您可以轻松地使用任何现有的处理鼠标事件的JavaScript代码,并且可以使用Internet Explorer 10中的某些笔或触摸设备按原样工作。确实,如果您不处理Pointer,IE10将触发鼠标事件作为最后的手段。代码中的事件。 这就是为什么即使开发人员从未想到某天有人会用这种方式用手指“点击”按钮或任何网页上的任何元素的原因。 因此,任何注册到mousedown和/或mouseup事件的代码都无需进行任何修改即可工作。 但是mousemove呢?

让我们回顾一下默认行为以回答该问题。 例如,让我们看一下这段代码:

 <! DOCTYPE  html >
< html >
< head >
    < title > Touch article sample 1 </ title >
</ head >
< body >
    < canvas  id ="drawSurface"  width ="400px"  height ="400px"  style =" border : 1px dashed black;">
    </ canvas >
    < script >
        var  canvas = document.getElementById( "drawSurface" );
        var  context = canvas.getContext( "2d" );
        context.fillStyle = "rgba(0, 0, 255, 0.5)" ;

        canvas.addEventListener( "mousemove" , paint, false );

        function  paint(event) {
            context.fillRect(event.clientX, event.clientY, 10, 10);
        }
    </ script >
</ body >
</ html >
 

它只是通过跟踪鼠标的移动在HTML5 canvas元素内绘制一些蓝色的10px x 10px的正方形。 要对其进行测试,请将鼠标移到该框中。 如果您有触摸屏,请尝试与画布进行交互以自行检查当前行为

默认样本 :不执行任何操作时的默认行为

结果只有MouseDown / Up / Click可以触摸。 即,您只能在点击屏幕时用触摸绘制蓝色方块,而在屏幕上移动手指时则不能。

您会看到,当您在canvas元素内移动鼠标时,它将绘制一系列蓝色方块。 但是使用touch代替,它只会在您点击canvas元素的确切位置绘制一个唯一的正方形。 尝试在canvas元素中移动手指时,浏览器将尝试在页面内平移,因为这是已定义的默认行为。

因此,您需要指定您想要覆盖浏览器的默认行为,并告诉其将触摸事件重定向到您的JavaScript代码,而不是尝试对其进行解释。 为此,将页面中不再对默认行为做出反应的元素作为目标,并将此CSS规则应用于它们:

 -ms-touch-action : auto | none | manipulation | double-tap-zoom | inherit ;

根据您要过滤或不过滤的内容,您可以使用各种值。 您将找到本文中描述的值: 构建触摸友好网站的准则

经典的用例是页面中有地图控件。 您想让用户在地图区域内平移和缩放,但保留页面其余部分的默认行为。 在这种情况下,您将只在显示地图的HTML容器上应用此CSS规则(-ms-touch-action:操作)。

在我们的例子中,添加以下CSS块:

 < style >
     #drawSurface
     {
        -ms-touch-action : none ; /* Disable touch behaviors, like pan and zoom */
     }
</ style >
 

现在会产生以下结果:

步骤1 :添加-ms-touch-action之后 : 无

结果 :禁用默认浏览器平移,并且MouseMove可以工作,但只能用一根手指

现在,当您在canvas元素内移动手指时,它的行为就像鼠标指针一样。 这很酷! 但是您很快就会问自己一个问题: “为什么这段代码只跟踪一根手指?” 好吧,这是因为我们只是在做IE10来提供基本的触摸体验,这是最后一步:映射您的一根手指来模拟鼠标。 据我所知,我们一次只使用一只鼠标。 因此,使用这种方法,一只鼠标==一根手指最多。 那么,如何处理多点触控事件呢?

步骤2:使用MSPointer事件而不是鼠标事件

采取任何现有代码,然后将注册替换为“ MSPointerDown / Up / Move”,将其注册为“ mousedown / up / move”,您的代码将直接支持IE10内的多点触控体验!

例如,在上一个示例中,更改以下代码行:

canvas.addEventListener( "mousemove" , paint, false );

对此:

canvas.addEventListener( "MSPointerMove" , paint, false );

您将得到以下结果:

步骤2 :使用MSPointerMove代替mousemove

结果多点触控作品

现在,您可以在系列中绘制与屏幕支持的接触点一样多的正方形! 更好的是,相同的代码适用于触摸,鼠标和笔。 例如,这意味着您可以用鼠标同时画一些线,而用手指画其他线。

如果您想根据输入的类型更改代码的行为,则可以通过pointerType属性值进行测试。 例如,假设我们要为手指绘制一些10px x 10px的红色正方形,为笔绘制5px x 5px的绿色正方形,为鼠标绘制2px x 2px的蓝色正方形。 您需要用以下命令替换以前的处理程序(paint函数):

 function  paint(event) {
    if  (event.pointerType) {
        switch  (event.pointerType) {
            case  event.MSPOINTER_TYPE_TOUCH:
                // A touchscreen was used
                // Drawing in red with a square of 10
                 context.fillStyle = "rgba(255, 0, 0, 0.5)" ;
                squaresize = 10;
                break ;
            case  event.MSPOINTER_TYPE_PEN:
                // A pen was used
                // Drawing in green with a square of 5
                 context.fillStyle = "rgba(0, 255, 0, 0.5)" ;
                squaresize = 5;
                break ;
            case  event.MSPOINTER_TYPE_MOUSE:
                // A mouse was used
                // Drawing in blue with a squre of 2
                 context.fillStyle = "rgba(0, 0, 255, 0.5)" ;
                squaresize = 2;
                break ;
        }

        context.fillRect(event.clientX, event.clientY, squaresize, squaresize);
    }
}

您可以在这里测试结果:

步骤2b :测试pointerType以测试触摸/笔或鼠标

结果 :您可以更改鼠标/笔/触摸行为,但是自2a以来,该代码在IE10 +中有效

如果您有幸拥有支持三种类型的输入的设备(例如BUILD2011期间的部分设备,例如Sony Duo 11, Microsoft Surface ProSamsung Tablet ),您将能够看到基于三种类型的绘图在输入类型上。 很好,不是吗?

但是,此代码仍然存在问题。 现在,它可以在IE10中正确处理所有类型的输入,但对于不支持MSPointer事件的浏览器(如IE9,Chrome,Firefox,Opera和Safari)根本不起作用。

步骤3:进行功能检测以提供后备代码

您可能已经知道,处理多浏览器支持的最佳方法是功能检测。 在我们的情况下,您需要对此进行测试:

window.navigator.msPointerEnabled

请注意,这只会告诉您当前的浏览器是否支持MSPointer。 它不会告诉您是否支持触摸。 要测试是否支持触摸,您需要检查msMaxTouchPoints

总而言之,要使代码具有IE10中的MSPointer并在其他浏览器中正常回退到鼠标事件,您需要这样的代码:

 var  canvas = document.getElementById( "drawSurface" );
var  context = canvas.getContext( "2d" );
context.fillStyle = "rgba(0, 0, 255, 0.5)" ;
if  (window.navigator.msPointerEnabled) {
    // Pointer events are supported.
     canvas.addEventListener( "MSPointerMove" , paint, false );
}
else  {
    canvas.addEventListener( "mousemove" , paint, false );
}

function  paint(event) {
    // Default behavior for mouse on non-IE10 devices
    var  squaresize = 2;
    context.fillStyle = "rgba(0, 0, 255, 0.5)" ;
    // Check for pointer type on IE10
    if  (event.pointerType) {
        switch  (event.pointerType) {
            case  event.MSPOINTER_TYPE_TOUCH:
                // A touchscreen was used
                // Drawing in red with a square of 10
                 context.fillStyle = "rgba(255, 0, 0, 0.5)" ;
                squaresize = 10;
                break ;
            case  event.MSPOINTER_TYPE_PEN:
                // A pen was used
                // Drawing in green with a square of 5
                 context.fillStyle = "rgba(0, 255, 0, 0.5)" ;
                squaresize = 5;
                break ;
            case  event.MSPOINTER_TYPE_MOUSE:
                // A mouse was used
                // Drawing in blue with a square of 2
                 context.fillStyle = "rgba(0, 0, 255, 0.5)" ;
                squaresize = 2;
                break ;
        }
    }

    context.fillRect(event.clientX, event.clientY, squaresize, squaresize);
}

同样,您可以在此处测试结果:

示例3 :检测msPointerEnabled以提供后备功能的功能

结果 :IE10的完整完整体验以及其他浏览器中的默认鼠标事件

步骤4:支持所有触控实现

如果您想进一步发展并支持所有浏览器和所有触摸实现,则有两种选择:

1 –编写代码以并行处理两个事件模型,如本文所述: 在所有浏览器中处理多点触摸和鼠标输入

2 –只需添加对HandJS的引用,HandJS是我的朋友David Catuhe编写的很棒的JavaScript polyfill库,如他的文章所述: HandJS a polyfill用于在每个浏览器上支持指针事件

正如我在本文简介中提到的那样,Microsoft最近向W3C提交了MSPointer Events规范以进行标准化。 W3C创建了一个新的工作组,并且已经根据Microsoft的建议发布了最后的工作草案 。 MS Open Tech团队最近还发布了您可能感兴趣的Webkit指针事件原型

尽管Pointer Events规范还不是标准,但您仍然可以利用David's Polyfill来实现支持该规范的代码,并为在所有现代浏览器中实现Pointer Events成为标准做好准备。 使用David的库,事件将被传播到IE10上的MSPointer,基于Webkit的浏览器上的Touch Events,最后是鼠标事件,作为最后的选择。 真是太酷了! 查看他的文章以发现并理解它的工作原理。 请注意,此polyfill届时也将非常有用,以通过鼠标事件的优雅后备支持较旧的浏览器。

要了解如何使用该库,请看一下本文: 感谢Hand.JS ,它为您展示了如何使用指针事件编写虚拟触摸操纵杆,从而创建了适用于所有Touch模型的通用虚拟触摸操纵杆 。 多亏了HandJS,它可以在具有相同代码库的Windows 8 / RT,Windows Phone 8,iPad / iPhone和Android设备上的IE10上运行!

识别简单手势

既然我们已经了解了如何处理多点触摸,那么让我们看看如何识别简单的手势(例如轻击或按住元素),然后再识别一些更高级的手势(例如平移或缩放元素)。

IE10提供了一个MSGesture对象,它将帮助我们。 请注意,此对象当前特定于IE10,而不是W3C提交的一部分。 用组合MSCSSMatrix元素(我们相当于WebKitCSSMatrix之一),你会看到,你可以建立一个非常简单的方法非常有趣的多点触控体验。 MSCSSMatrix实际上代表了一个4×4齐次矩阵,该矩阵使文档对象模型(DOM)脚本能够访问CSS 2-D和3-D Transforms功能。 但是在开始之前,让我们从基础开始。

基本概念是首先向MSPointerDown注册事件处理程序 。 然后,在负责处理MSPointerDown的处理程序内部,您需要选择 要发送到MSGesture对象的指针,以使其检测特定的手势。 然后它将触发以下事件之一: MSGestureTapMSGestureHoldMSGestureStartMSGestureChangeMSGestureEndMSInertiaStart 。 然后,MSGesture对象将所有提交的指针作为输入参数,并将在它们之上应用手势识别器以提供一些格式化的数据作为输出。 您唯一需要做的就是选择/过滤您想成为手势一部分的指针(基于它们的ID,屏幕上的坐标等等)。 之后,MSGesture对象将为您完成所有操作。

示例1:处理保持手势

我们将看到如何保存元素(一个简单的div,其中包含图像作为背景)。 保留元素后,我们将添加一些角以向用户表明他当前已选择此元素。 这些角将通过动态创建四个div来生成,这些div添加到图像每个角的顶部。 最后,一些CSS技巧将以一种聪明的方式使用变换和线性渐变来获得如下内容:

image

该序列将是以下序列:

1 –在您感兴趣的HTML元素上注册MSPointerDown和MSPointerHold事件

2 –创建一个MSGesture对象,该对象将针对相同的HTML元素
3 –在MSPointerDown处理程序内,将要监视的各种PointerID添加到MSGesture对象(根据您要实现的目标全部或部分)。

4 –在MSPointerHold事件处理程序内,检查详细信息是否用户刚刚开始执行保持手势(MSGESTURE_FLAG_BEGIN标志)。 如果是这样,请添加角点。 如果不是,请将其删除。

这将导致以下代码:

 <! DOCTYPE  html >
< html >
< head >
    < title > Touch article sample 5: simple gesture handler </ title >
    < link  rel ="stylesheet"  type ="text/css"  href ="toucharticle.css" />
    < script  src ="Corners.js"></ script >
</ head >
< body >
    < div  id ="myGreatPicture"  class ="container" />
    < script >
        var  myGreatPic = document.getElementById( "myGreatPicture" );
        // Creating a new MSGesture that will monitor the myGreatPic DOM Element
         var  myGreatPicAssociatedGesture = new  MSGesture();
        myGreatPicAssociatedGesture.target = myGreatPic;

        // You need to first register to MSPointerDown to be able to
        // have access to more complex Gesture events
         myGreatPic.addEventListener( "MSPointerDown" , pointerdown, false );
        myGreatPic.addEventListener( "MSGestureHold" , holded, false );

        // Once pointer down raised, we're sending all pointers to the MSGesture object
         function  pointerdown(event) {
            myGreatPicAssociatedGesture.addPointer(event.pointerId);
        }

        // This event will be triggered by the MSGesture object
        // based on the pointers provided during the MSPointerDown event
         function  holded(event) {
            // The gesture begins, we're adding the corners
             if  (event.detail === event.MSGESTURE_FLAG_BEGIN) {
                Corners.append(myGreatPic);
            }
            else  {
                // The user has released his finger, the gesture ends
                // We're removing the corners
                 Corners.remove(myGreatPic);
            }
        }

        // To avoid having the equivalent of the contextual  
        // "right click" menu being displayed on the MSPointerUp event, 
        // we're preventing the default behavior
         myGreatPic.addEventListener( "contextmenu" , function  (e) {
            e.preventDefault();    // Disables system menu
         }, false );
    </ script >
</ body >
</ html > 

结果如下:

尝试只是点击或鼠标单击元素,什么也不会发生。 触摸并保持只用一根手指在图像上,或在图像上长按鼠标,将出现角。 松开手指,角落消失。

触摸并保持两个或多个手指在图像上,仅当一根唯一的手指按住元素时,才会触发Hold手势,因此不会发生任何事情。

注意:白色边框,边角和背景图像是通过toucharticle.css中定义的CSS设置的。 Corners.js只需创建四个div(带有append函数),然后将它们放置在具有适当CSS类的每个角落的主要元素上方。

不过,当前的结果让我有些不满意。 握住图片后,只要稍稍移动手指,MSGESTURE_FLAG_CANCEL标志就会升起并被处理程序捕获,该处理程序会去除角落。 我希望仅在用户将手指松开到图片上方的任何位置时,或者将手指从图片所界定的盒子中移出后,才移开边角。 为此,我们将只删除MSPointerUp或MSPointerOut上的角。 而是提供以下代码:

 var  myGreatPic = document.getElementById( "myGreatPicture" );
// Creating a new MSGesture that will monitor the myGreatPic DOM Element
 var  myGreatPicAssociatedGesture = new  MSGesture();
myGreatPicAssociatedGesture.target = myGreatPic;

// You need to first register to MSPointerDown to be able to
// have access to more complex Gesture events
 myGreatPic.addEventListener( "MSPointerDown" , pointerdown, false );
myGreatPic.addEventListener( "MSGestureHold" , holded, false );
myGreatPic.addEventListener( "MSPointerUp" , removecorners, false );
myGreatPic.addEventListener( "MSPointerOut" , removecorners, false );

// Once touched, we're sending all pointers to the MSGesture object
 function  pointerdown(event) {
    myGreatPicAssociatedGesture.addPointer(event.pointerId);
}

// This event will be triggered by the MSGesture object
// based on the pointers provided during the MSPointerDown event
 function  holded(event) {
    // The gesture begins, we're adding the corners
     if  (event.detail === event.MSGESTURE_FLAG_BEGIN) {
        Corners.append(myGreatPic);
    }
}

// We're removing the corners on pointer Up or Out
 function  removecorners(event) {
    Corners.remove(myGreatPic);
}

// To avoid having the equivalent of the contextual  
// "right click" menu being displayed on the MSPointerUp event, 
// we're preventing the default behavior
 myGreatPic.addEventListener( "contextmenu" , function  (e) {
    e.preventDefault();    // Disables system menu
 }, false );

现在提供了我正在寻找的行为:

示例2:处理秤,平移和旋转

最后,如果要缩放,平移或旋转元素,只需编写几行代码即可。 您需要首先注册到MSGestureChange事件。 此事件将通过MSGestureEvent对象文档中描述的各种属性(例如当前应用于HTML元素的rotationscaletranslationXtranslationY)发送给您。

更好的是,默认情况下,MSGesture对象免费提供惯性算法。 这意味着您可以使用HTML元素,然后用手指将其扔到屏幕上,动画将为您处理。

最后,为了反映MSGesture发送的这些更改,您需要相应地移动元素。 最简单的方法是应用一些CSS转换来映射与手指手势匹配的旋转,缩放,平移细节。 为此,请使用MSCSSMatrix元素。

总之,如果您想处理所有先前示例中的酷手势,请像下面这样注册该事件:

myGreatPic.addEventListener( "MSGestureChange" , manipulateElement, false );

并使用以下处理程序:

 function  manipulateElement(e) {
    // Uncomment the following code if you want to disable the built-in inertia 
    // provided by dynamic gesture recognition
    // if (e.detail == e.MSGESTURE_FLAG_INERTIA)
    // return;

    // Get the latest CSS transform on the element
     var  m = new  MSCSSMatrix(e.target.currentStyle.transform); 
    e.target.style.transform = m
    .translate(e.offsetX, e.offsetY) // Move the transform origin under the center of the gesture
     .rotate(e.rotation * 180 / Math.PI) // Apply Rotation
     .scale(e.scale) // Apply Scale
     .translate(e.translationX, e.translationY) // Apply Translation
     .translate(-e.offsetX, -e.offsetY); // Move the transform origin back
 }

这为您提供了最终样本:

尝试用一个或多个手指将图像移动并扔到黑色区域内。 还尝试用两个或更多个手指缩放或旋转元素。 结果很棒,并且代码非常简单,因为所有复杂性都由IE10本地处理。

直接链接到所有样本

如果您没有可用的IE10触摸屏体验,并且想知道此页面上的示例如何工作,则可以在此处单独查看每个示例:

简单触摸默认示例,不做任何事情
使用CSS -ms-touch-action的简单触摸示例步骤1
使用基本的MSPointerMove实现的简单触摸示例步骤2a
简单的触摸示例步骤2b,具有pointerType区分
带有MSPointers和鼠标后备的简单触摸示例步骤3
MSGesture示例1:MSGestureHold处理程序
MSGesture示例1b:MSGestureHold处理程序
MSGesture示例2:MSGestureChange

相关资源:

W3C指针事件规范

在所有浏览器中处理多点触摸和鼠标输入 :polyfill库,将来应该对很多开发人员有帮助
指针和手势事件

使用手势事件超越平移,缩放和点击

IE Test Drive Browser Surface极大地启发了许多嵌入式演示

–尝试在IE10中使用Touch做一些很棒的游戏:

Contre Jour ,阅读了一篇非常有趣的“ 幕后”文章

Atari Arcade Games ,还请阅读这篇非常有用的文章: 使用CreateJS构建Atari,其中详细介绍了在所有平台上支持Touch的选择。

–录制会话3-140: 触摸屏,手写笔和鼠标,我的天!

逻辑上,本文将共享所有详细信息以及与其他资源的关联链接, 您现在就可以在网站和Windows Store应用程序中实现MSPointer Events模型 。 然后,您就有机会轻松地增强用户在Internet Explorer 10中的体验。


本文是Internet Explorer团队的HTML5技术系列的一部分。 通过三个月的免费BrowserStack跨浏览器测试@ http://modern.IE来尝试本文中的概念


From: https://www.sitepoint.com/unifying-touch-and-mouse-with-pointer-events/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值