文章目录
  1. 1. 需求
  2. 2. 分析
  3. 3. 实现

需求

有个需求是要求实现屏幕内容下滑隐藏导航栏,上滑显示导航栏的效果。

分析

对于移动端来说,手指在屏幕上的事件主要通过触摸事件来触发,判断手指上滑还是下滑,主要是判断手指进入屏幕到离开屏幕的角度,在js中,就利用到Math.atan2(y,x)函数,这个函数的作用是返回从x轴正方向通过逆时针旋转到达坐标点(x, y)所经过的角度(单位为弧度),返回值介于 [-π, π] 之间。这里需要脑筋急转弯一下,大家还记得弧度是怎么求来的吗?弧度的公式是:

1
atan2(y,x) = 角度*π/180度,例如60度 = 3/π

好了,知道这个函数怎么求后,就可以根据这个函数求到角度,然后就可以判断:

  1. 当 0<角度<180 时,表示上滑。
  2. 当 -180<角度<0 时,表示下滑。

其实也可以不用角度,直接用弧度也是可以的,那就变成:

  1. 当 0<角度<π 时,表示上滑。
  2. 当 -π<角度<0 时,表示下滑。

其实,这样就可以根据角度或弧度表示上右下左四哥方向了,来一张示意图:

1
2
3
4
5
6
7
8
9
       Y/\
\ 上 | /
\ | /
左 \ | / 右
________|_________>X
|
/ | \
/ | \
/ 下 | \

好,思路有了,那就开干吧,函数里的y,x怎么来的,其实就是手指进入屏幕到离开屏幕的纵横坐标差,当然这个差是分正负值的。

实现

基本代码就是下面那样了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
;(function () {
//返回角度
function GetSlideAngle(dx, dy) {
return Math.atan2(dy, dx) * 180 / Math.PI;
}

//根据起点和终点返回方向 1:向上,2:向下,0:未滑动
function GetSlideDirection(startX, startY, endX, endY) {
var dy = startY - endY;
var dx = endX - startX;
var result = 0;

//如果滑动距离太短
if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
return result;
}

var angle = GetSlideAngle(dx, dy);

if(angle >= 0 && angle < 180) {
result = 1;
}else if (angle >= -180 && angle < 0) {
result = 2;
}

return result;
}

var handler = function (ev) {
var endX, endY;
endX = ev.changedTouches[0].pageX;
endY = ev.changedTouches[0].pageY;
var direction = GetSlideDirection(startX, startY, endX, endY);
switch(direction) {
case 0:
//alert("没滑动");
break;
case 1:
//向上隐藏
//如果文本的高度小于屏幕可见区域的高度
if(document.documentElement.clientHeight >= document.body.clientHeight){
//
}else{

var scrollTop=0;
if(document.documentElement&&document.documentElement.scrollTop)
{
scrollTop=document.documentElement.scrollTop;
}
else if(document.body)
{
scrollTop=document.body.scrollTop;
}

//如果滚动的高度小于导航栏的高度
if(scrollTop<=$('[data-sel=nav-header]').height()){
//
}else{
$('[data-sel=nav-header]').addClass('nav-slide-up');
}
}

break;
case 2:
//向下显示
$('[data-sel=nav-header]').removeClass('nav-slide-up');
break;
default:
}
}

//滑动处理
var startX, startY;
document.addEventListener('touchstart',function (ev) {
startX = ev.touches[0].pageX;
startY = ev.touches[0].pageY;
}, false);

document.addEventListener('touchend',handler, false);
document.addEventListener('touchcancel',handler, false);

})();

每个触摸事件都包括了三个触摸列表:

  1. touches :当前位于屏幕上的所有手指的一个列表。
  2. targetTouches :位于当前DOM元素上的手指的一个列表。
  3. changedTouches :涉及当前事件的手指的一个列表。

用一个手指接触屏幕,触发事件,此时这三个属性有相同的值。

用第二个手指接触屏幕,此时,touches有两个元素,每个手指触摸点为一个值。当两个手指触摸相同元素时,targetTouches和touches的值相同,否则targetTouches 只有一个值。changedTouches此时只有一个值,为第二个手指的触摸点。

用两个手指同时接触屏幕,此时changedTouches有两个值,每一个手指的触摸点都有一个值

手指滑动时,三个值都会发生变化

一个手指离开屏幕,touches和targetTouches中对应的元素会同时移除,而changedTouches仍然会存在元素。
手指都离开屏幕之后,touches和targetTouches中将不会再有值,changedTouches还会有一个值,此值为最后一个离开屏幕的手指的接触点。
来自http://blog.sina.com.cn/s/blog_468530a60102wzkw.html

代码中为何同时用touchendtouchcancel事件呢,那是为了兼容安卓的一些浏览器,详情可以看博客中后面讲到的安卓移动端滑动不支持touchend事件

文章目录
  1. 1. 需求
  2. 2. 分析
  3. 3. 实现