最近接触vue.js移动端开发。自己写一个类似微博的图片预览器来学习一下移动端手势的实现和css3的属性的使用。
目标分析
首先分析图片预览器的功能:
1.图片显示
2.缩放(swipe)图片
3.拖拽图片(drag)
3.双击(doubleTap)放大/缩小
4.单击(tap)隐藏图片
5.左右滑到前一页或后一页
分析的手势有:单击(tap) 双击(doubleTap) 缩放(swipe) 拖拽(drag)
都是由有三个事件构成:touchstart, touchmove,touchend.
手势解析:
单击(tap)
手势分解:点击进入touchstart事件,touchmove几乎没有,但是也要为用户预留点击时的微小移动,再触发touchend事件。在本组件中touchmove移动半径设置为小于10
从触摸屏幕到离开屏幕的时间是非常短的,所以touchstart事件到touchend事件之间的时间间隔是非常小的,不超过500毫秒。t2-t1<500
代码实现:
onTouchstart(evt){
this.startTime = new Date().getTime();
if(evt.touches.length>1){//双手势
}else{//单手势
this.start.x = evt.touches[0].pageX;
this.start.y = evt.touches[0].pageY;
}
}
onTouchMove(evt){
this.move.x = evt.touches[0].pageX;
this.move.y = evt.touches[0].pageY;
}
onTouchEnd(evt){
let timestamp = new Date().getTime();
if(this.move.x !== null && Math.abs(this.move.x - this.start.x)< 10 ||this.move.y !== null && Math.abs(this.move.y - this.start.y)<10){
//有移动的情况
}else{
//单击
if(timestamp - this.startTime < 500){
//触发单击事件
}
}
}
双击(doubleTap)
双击事件包含了两次单击事件,区分在于两次单击的时间判断,两次单击的时间,也就是touchstart触发的时间间隔,不超过300毫秒,当然,也要给用户一些触摸移动的像素,将两个点的x,y轴上的距离控制在10像素内。
实现:
touchStartFn(evt){
this.startTime = new Date().getTime();
if(evt.touches.length>1){//双手势
}else{//单手势
this.start.x = evt.touches[0].pageX;
this.start.y = evt.touches[0].pageY;
if(this.previousTouchPoint){//上一次的触摸点
if(Math.abs(this.start.x- this.previousTouchPoint.startX)<10 &&Math.abs(this.start.y- this.previousTouchPoint.startY)<10 && this.startTime - this.previousStartTime < 300){
//触发双击的事件
...
}
}
this.previousTouchTime = this.startTime;
this.previousTouchPoint = {
startX:this.start.x,
startY:this.start.y
};
}
}
如果一个页面上既有单击tap事件,又有双击doubleTap事件,怎么办?用上述方法,两种事件会相互冲突,光靠时间和偏移量来控制是不够的。
解决思路:初始化this.previousTouchTime = 0;this.previousTouchPoint = undefined;在执行完双击事件后将this.previousTouchPoint置为undefined,this.previousTouchTime置为0。在触摸结束事件中添加一个setTimeout来监听是否有新的单击事件发生。如果新单击事件发生,则去除这个监听,如果没有,则触发单击事件
touchEndFn(evt){
let timer = setTimeout(()=>{
if(this.previousTouchPoint !== undefined && this.previousTouchTime !== 0){
//触发单击事件
...
}else{
clearTimeout(timer);//去除监听
}
},300);
}
这样,单击和双击事件就不会冲突了。
缩放(swipe)
缩放是个双手势触摸过程,触摸点会有两个,也就是Touch对象会有两个。并在触摸滑动过程中,要计算出缩放倍数。
point1与point2的触摸开始位置和结束位置都会有偏移,缩放的倍数计算:scale = r2/r1
onTouchStart(evt){
if(evt.touches.length>1){//双手势
let point1 = evt.touches[0];
let point2 = evt.touches[1];
let deltaX = Math.abs(point2.pageX - point1.pageX);
let deltaY = Math.abs(point2.pageY - point1.pageY);
this.distance = Math.sqrt(deltaX*deltaX+deltaY*deltaY);//初始时候的距离,r1
}else{
//单手势事件
}
}
onTouchMove(evt){
if(evt.touches.legnth>1){
let point1 = evt.touches[0];
let point2 = evt.touches[1];
let deltaX = Math.abs(point2.pageX - point1.pageX);
let deltaY = Math.abs(point2.pageY - point1.pageY);
let distance = Math.sqrt(deltaX*deltaX+deltaY*deltaY);
if(this.distance){
this.swipeScale = distance/this.distance;
//执行缩放事件
}
}else{//单手势事件}
}
拖拽/移动
移动事件就是在触摸屏幕并移动的时候,图片或者元素能够跟随手指一起移动。这是一个单手势操作,屏幕上只要一个触摸点。在touchmove发生时将坐标位置向减得到位移量。
onTouchStart(evt){
if(evt.touches.length>1){//双手势
}else{//单手势
this.start.x = evt.touches[0].pageX;
this.start.y = evt.touches[0].pageY;
}
}
onTouchMove(evt){
if(evt.touches.length>1){//双手势
}else{//单手势
let deltaX = evt.touches[0].pageX - this.start.x;
let deltaY = evt.touches[0].pageY- this.start.y;
//触发移动事件
}
}
图片放大功能的实现
我采用了css3的transform属性进行缩放,并且设置transform-origin来设置缩放中心位置。缩放的倍数为缩放事件计算出的this.swipeScale
缩放代码:
$img.style.transform = "scale("+this.swipeScale +")";
$img.style.transformOrigin = x + " " + y;
下一节将讲用vue.js具体实现过程
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。