手势的实现常用的HTML5手势分为两类,单点手势和两点手势。单点手势包括tap(点击)、doubletap(双击)、longtap(长按)、swipe(波浪)和move(移动)。两点手势包括捏合(缩放)和旋转(旋转)。接下来,我们实现一个检测这些手势的javaScript库,并使用这个手势库来制作炫酷的交互效果。我们不会在这里详细介绍移动手势检测。综上所述,每发生一次touchmove事件,减去两个位移点之间的坐标位置即可。点击(tap)手势检测的关键是利用touchstart、touchmove、touchend三个事件对手势进行分解。那么如何分解点击事件呢?touchstart时进入点击检测,只有一个触摸点。因为点击事件仅限于一根手指的移动。touchmove事件没有发生或者touchmove在一个小范围内(如下图)。将touchmove限制在一个很小的范围内是为了给用户一定的冗余度,因为不能保证用户的手指在触摸屏幕时不会有轻微的移动。3.touchend发生在touchstart后的很短时间内(如下图)。该时间段的阈值以毫秒为单位,用于限制手指接触屏幕的时间。因为点击事件从头到尾都很快。通过以上流程,就可以开始实现点击事件监听了。_getTime(){返回新日期().getTime();}_onTouchStart(e){//记录touch的起始位置this.startX=e.touches[0].pageX;this.startY=e.touches[0].pageY;if(e.touches.length>1){//多点监控...}else{//记录触摸开始时间this.startTime=this._getTime();}}_onTouchMove(e){...//记录手指移动的位置this.moveX=e.touches[0].pageX;this.moveY=e.touches[0].pageY;...}_onTouchEnd(e){让时间戳=this._getTime();if(this.moveX!==null&&Math.abs(this.moveX-this.startX)>10||this.moveY!==null&&Math.abs(this.moveY-this.startY)>10){...}else{//手指移动的位移应小于10个像素,手指与屏幕的接触时间应为500毫秒if(timestamp-this.startTime<500){this._emitEvent('onTap')}}}Web前端开发学习Q-q-u-n:784783012,分享学习方法和需要注意的小细节,持续更新最新的教程和学习方法(详细的前端项目实战教学视频)doubletap(doubletap)和单击、双击事件一样,也需要我们对手势进行量化。双击事件是手指动作。所以在touchstart的时候,我们需要判断此时屏幕有多少个接触点。一个双击事件包含两个独立的点击行为。理想情况下,两次点击应落在屏幕上的同一位置。为了给用户一定的冗余空间,两次点击的坐标点之间的距离限制在10个像素以内。双击事件本质上是两次快速点击。也就是说,两次点击之间的时间很短。通过一定的测试量化后,我们将两次点击的时间间隔设置为300毫秒。注意,在双击事件中,我们检测了相邻两个touchstart事件的位移和时间间隔。_onTouchStart(e){if(e.touches.length>1){...}else{if(this.previousTouchPoint){//相邻两个touchstart之间的距离要小于10,时间间隔要小超过300毫秒if(Math.abs(this.startX-this.previousTouchPoint.startX)<10&&Math.abs(this.startY-this.previousTouchPoint.startY)<10&&Math.abs(this.startTime-this.previousTouchTime)<300){this._emitEvent('onDoubleTap');}}//保存最后一次touchstart的时间和位置信息this.previousTouchTime=this.startTime;this.previousTouchPoint={startX:this.startX,startY:this.startY};}}长按(longpress)长按应该是最容易分解的手势了。我们可以这样分解:在touchstart发生后的很长一段时间内,如果没有发生touchmove或者touchend事件,那么就会触发长按手势。长按是一根手指的行为,需要检测屏幕上是否只有一个接触点。如果手指在空间上移动,则取消长按事件。如果手指在屏幕上停留时间超过800ms,则触发长按手势。如果手指停留在屏幕上的时间小于800ms,即touchend发生后800ms内触发touchend,则取消长按事件。_onTouchStart(e){clearTimeout(this.longPressTimeout);if(e.touches.length>1){}else{this.longPressTimeout=setTimeout(()=>{this._emitEvent('onLongPress');});}}_onTouchMove(e){...clearTimeout(this.longPressTimeout);...}_onTouchEnd(e){...clearTimeout(this.longPressTimeout);...}Zoom(pinch)Zoom是一个非常有趣的手势,你还记得第一代iPhone上捏合缩放图片给你带来的震撼吗?即便如此,捏合手势的检测还是相对简单的。缩放是双指行为,需要检测屏幕上是否有两个接触点。缩放比例的量化是通过两个缩放行为之间的距离的比值得到的,如下图所示。所以缩放的核心是得到两个接触点之间的直线距离。//勾股定理_getDistance(xLen,yLen){returnMath.sqrt(xLen*xLen+yLen*yLen);}这里,xLen是两个接触点的x坐标差的绝对值,yLen对应的是y坐标差的绝对值。_onTouchStart(e){if(e.touches.length>1){让point1=e.touches[0];让point2=e.touches[1];让xLen=Math.abs(point2.pageX-point1.pageX);让yLen=Math.abs(point2.pageY-point1.pageY);this.touchDistance=this._getDistance(xLen,yLen);}else{...}}在_onTouchStart函数中获取并保存touchstart两个触摸点之间的距离。_onTouchMove(e){if(e.touches.length>1){让xLen=Math.abs(e.touches[0].pageX-e.touches[1].pageX);让yLen=Math.abs(e.touches[1].pageY-e.touches[1].pageY);让touchDistance=this._getDistance(xLen,yLen);如果(this.touchDistance){让pinchScale=touchDistance/this.touchDistance;this._emitEvent('onPinch',{scale:pinchScale-this.previousPinchScale});this.previousPinchScale=pinchScale;}}else{...}}Rotation(旋转)旋转手势需要检测两个比较重要的值,一是旋转的角度,二是旋转的方向(顺时针或逆时针)。旋转角度和方向的计算需要通过向量的计算得到,本文不再展开。首先,你需要得到向量的旋转方向和角度。//这两个方法属于向量计算_getRotateDirection(vector1,vector2){returnvector1.x*vector2.y-vector2.x*vector1.y;}_getRotateAngle(vector1,vector2){letdirection=this._getRotateDirection(vector1,vector2);方向=方向>0?-1:1;让len1=this._getDistance(vector1.x,vector1.y);让len2=this._getDistance(vector2.x,vector2.y);让先生=len1*len2;如果(先生===0)返回0;让点=vector1.x*vector2.x+vector1.y*vector2.y;设r=点/mr;如果(r>1)r=1;如果(r<-1)r=-1;返回Math.acos(r)*方向*180/Math.PI;然后,当手指移动时,我们调用该方法来获取旋转方向和角度。_onTouchStart(e){...if(e.touches.length>1){this.touchVector={x:point2.pageX-this.startX,y:point2.pageY-this.startY};}...}_onTouchMove(e){...if(this.touchVector){让向量={x:e.touches[1].pageX-e.touches[0].pageX,y:e.touches[1].pageY-e.touches[0].pageY};让angle=this._getRotateAngle(vector,this.touchVector);this._emitEvent('onRotate',{angle});this.touchVector.x=vector.x;this.touchVector.y=vector.y;}...}实战完毕,我们的手势系统到这里就完成了。接下来我们要测试这个系统在实战中是否靠谱,做一个简单的支持图片缩放、旋转、移动、长按的图片浏览器。首先,做好DOM规划。和“之前”一样,我们的事件监听机制并不直接作用于图片,而是作用于图片的父元素。然后,就可以开始使用上面的手势检测系统了。render(){返回(">
