管中窥豹——pullPage的简单实现思路

今天看到一个响应式的页面,看完才感觉原来最开始学html的时候,我就会做响应式页面了。后面因为CSS+DIV网页布局的出现,才使得元素被束缚。。。
感觉收获最大的就是,知道了媒体查询和rem的使用方向上面的不同:

  • 媒体查询:针对页面为了适应不同设备,说白了就是为了让页面在不同的设备(pc端,移动端,平板)上显示的有美感。
  • rem :更多是针对移动端布局,只要是为了实现让页面在所有的移动端设备上看起来都是一样.

好了,话题回到fullpage.js的实现过程中来。
前端时间看到很多pc段页面都是用这个插件。今天再github上面看了看用法,开始用自己思路想了一个小时,后面看了看源码。这里总结下fullpage.js的实现思路;

fullpage.js大致思路。

最开始,不用说当然是一个html,然后给加上样式

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{margin:0; padding:0;}
*{box-sizing: border-box;}
*{margin:0; padding:0;}
*{box-sizing: border-box;}
html,body,section{
width:100%;
height:100%;
}
body{
overflow:hidden;
}
section>div{
height:100%;
text-align: center;
}
.box:nth-of-type(1){
background:yellow;
}
.box:nth-of-type(2){
background:green;
}
.box:nth-of-type(3){
background:red;
}
.box:nth-of-type(4){
background:pink;
}
</style>

</head>
<body>
<section>
<div class="box">page1</div>
<div class="box">page2</div>
<div class="box">page3</div>
<div class="box">page4</div>
</section>
</body>
</html>
这里为了好区分,我给每一个div都加上不同的颜色。

然后我们就会得到这样一幅图
0_1468426647980_示意图.gif

如何滑动

得到这样一个图还是不行啊,到底如何让他根据我的动作动起来呢??我这里想到了JS

获取滑动的距离

  • 因为每次要滑动的距离 都是一个窗口的大小,所以很简单 这里要做的就是先确定 滑动的距离
    1
    var fullHeight=document.documentElement.clientHeight;

获取滑动的方向

  • 知道了滑动距离之后,我还需要知道他到底是向上滑还是向下滑动啊,这样我也好作出与之相对应的操作对应。

对此我当时的想法是,我能不能先一开始记录下我所对应的窗口windowscolltop值的大小,然后和我操作后的值比大小,从而判断我是想上滑动的还是向下滑动的。

1
2
3
4
5
6
7
8
9
10
oldScrolltop=$(window).scrollTop();
$(window).on("scroll",function(){
var newScrolrrtop=$(window).scrollTop();
var result=newScrolrrtop-oldScrolltop;
if(result>0){
console.log("我在向下滑动。");
}else{
console.log("我在向上滑动")
}
})

0_1468428278945_upload-cd0921e4-18e5-4d75-a2a5-bef1c5e3f824
然而结果却是,不管我上滑还是下滑,都是console.log(“我在向上滑动”),这里肯定哪里出错了。


后面排查的时候发现。这里有个严重的错误:

  • 我最开始就定义了oldScroll 相当于我每次都是用最新的窗口滚动距离,减去初始的那个窗口滚动距离,很明显这一开始就错了。
    后面发现 应该这样弄
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    oldScrolltop=$(window).scrollTop();
    $(window).on("scroll",function(){
    var newScrolltop=$(window).scrollTop();
    var result=newScrolltop-oldScrolltop;
    oldScrolltop=newScrolltop;
    if(result>0){
    console.log("我在向下滑动。");
    }else{
    console.log("我在向上滑动")
    }
    })

这样就相当于:

  • 我下一次的”旧数据”是我前一次的”新数据”
  • 虽然有点绕,但是我相信大家可以忽略我第一句话,直接看代码就能明白。。。。
    0_1468428726088_upload-4634789a-ffe3-4332-b1e1-94e28053c0de
    这样就能确保我每次滑动鼠标,都会给我反馈一个正确的滑动方向。

获取方向之后的行动

当获取到了。每次滑动时的方向之后,我们要做什么?————当然是 让这个”玩意”上下动起来啊。难道还在控制台看我向上滚了,向下滚了。。。

要使得屏幕上下滚动,第一时间想到的就是$(window).srollTop(),当我们知道每次鼠标滑动的方向元素内部的高度这样就很好做了:

  • 如果鼠标是向上滚动,那么我们就直接让窗口的距离向下滚动一个fullHeight的距离;
  • 如果鼠标是向下滚动,那么我们就直接让窗口的距离向上滚动一个fullHeight的距离;
    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
    这里我们把上面的代码封装成一个函数。
    var fullHeight=document.documentElement.clientHeight,
    oldScrolltop=$(window).scrollTop(),
    key;
    $(window).on("scroll",function(){
    if(key)return;
    key=true;
    var response= getScrolltop();
    if(response==="down"){
    $(window).scrollTop($(window).scrollTop()+fullHeight);
    key=false;

    }else{
    $(window).scrollTop($(window).scrollTop()-fullHeight);
    key=false;
    }
    })


    function getScrolltop(){
    var newScrolltop=$(window).scrollTop(),
    result=newScrolltop-oldScrolltop;
    oldScrolltop=newScrolltop;
    if(result>0){
    return "down";
    }else{
    return "up";
    }
    }

然后试着 试了试,却发现了问题。
再滑动的时候,视窗类的元素会从第一个直接滑到最后一个。很明显这不是我们想要的样子。


另一种尝试,wheel事件。

这里我们把监听事件的类型从,监听滚动事件scroll改成wheel监听鼠标的滚轮事件.

1
2
3
$(window).on("wheel",function(){
console.log("我滑动了。")
})

但是这样有一个问题:
因为我之前判断滚动方向是通过比较前后$(window).scrollTop值的大小来判断的,这里其实可以通过另外一个值来直接判断。省去比较前后$("window").scrollTop值的比较,

1
2
3
$(window).on("wheel",function(e){
console.log(e)
})

当鼠标滑轮向下滚动时:
0_1468461389602_upload-f4873a89-3a7d-413d-8312-3510981f4daf


当鼠标滑轮向上滚动时:
0_1468461182518_upload-38ffde72-28df-4ffc-94c2-b24561f9b270


这样一来我们就只需要通过判断e.originalEvent.deltaY这个值的大小,从而就能知道鼠标是向上滚动还是向下滚动了。

整理之后 我们代码就变成这样了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var fullHeight=document.documentElement.clientHeight,
oldScrolltop=$(window).scrollTop(),
key;

$(window).on("wheel",function(e){
if(key)return;
key=true;
var response= e.originalEvent.deltaY;
if(response>0){
$(window).scrollTop($(window).scrollTop()+fullHeight);
key=false;

}else{
$(window).scrollTop($(window).scrollTop()-fullHeight);
key=false;
}
})

但是这样 功能也算大致实现了。有点小问题,当鼠标滑动过快的时候,我们发现屏幕会一下子从page1page2
这里用animate稍微改进下。

1
2
3
4
5
6
7
8
9
10
11
12
13
var fullHeight=document.documentElement.clientHeight,
oldScrolltop=$(window).scrollTop(),
key;

$(window).on("wheel",function(e){
if(key)return;
key=true;
var response= e.originalEvent.deltaY;
var dection =response>0?"+=":"-=";
$("body").animate({"scrollTop":dection+fullHeight},1000,function(){
key=false;
})
})

到此为止.fullpage.js的大致功能就已经实现了。
不过既然是自己动手造轮子,就弄点稍微好一点。这里其实还可以在做一点加工,让他适应手机端和PC端。


让fullpage.js使用手机端

我们知道手机端屏幕和PC端屏幕。最大的不同就是:

  • 手机端没有鼠标啊。你让我怎么用wheel事件.
  • 不过手机端上多了一个touch事件

这样问题就很好解决了。我们同时监听这两个事件,不就是相当于完成了移动端和PC端的自适应??

在移动端中,因为有了touch事件,如果要监控判断用户在移动端是向上滑动,还是向下滑动(这里简单起见,不考像左右滑动ongoing的,当然判断左右滑动和上下滑动类似);而且在移动端中我更倾向于使用css3来代替animate;

好了不多说,我们直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$("body").on("touchstart", function(e) {
e.preventDefault();
startY = e.originalEvent.changedTouches[0].pageY;
});
$("body").on("touchend", function(e) {
e.preventDefault();
moveEndY = e.originalEvent.changedTouches[0].pageY;
Y = moveEndY - startY;

if(Y>0) {
console.log("向下滑");
}else{
console.log("向上滑");
}
});


这样我就直接可以在`touch`事件开始之前,记录一个值,然后在`touch`事件结束的时候,再记录一个值。
然后比较两者之间的大小,当大于某个值的时候,作出相对应的动作(当然这个值的大小我们可以规定)