浅析H5下拉刷新和上拉加载

随着科技的发展,移动互联网早已进入到我们的生活当中,为了给用户更好的使用体验,出现了下拉刷新和上拉加载更多数据的交互方式,出现的频率也很高.也有很多第三方开源插件,如:iScrollbetter-scroll等,下面我们就来简单实现下拉刷新和上拉加载吧.

原理分析

首先不论是下拉还是上拉,都是一个移动端的持续动作,所以我们要监听touchstarttouchmovetouchend来实现.

关于内容容器的拖动,我们可以使用css3来实现,如果浏览器不支持css3,则改变容器的定位来达到这样对目的,不过现在不支持 css3 的浏览器应该都没有了.

1.监听touchstart事件 2.监听touchmove事件,并计算移动偏移量,移动偏移量不能超过最大值,根据移动的距离来判断拉动方向,并将移动偏移量赋值给要移动对容器 3.监听touchend事件,执行刷新或者加载更多操作,完成操作后将容器复位

demo 点我

代码实现

html+css
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
<!-- css -->
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
#scroller {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
.refresh-text {
top: 0;
z-index: -1;
width: 100%;
height: 40px;
color: #333;
font-size: 14px;
line-height: 40px;
position: absolute;
text-align: center;
}
.loading-text {
bottom: 0;
z-index: -1;
width: 100%;
height: 40px;
color: #333;
font-size: 14px;
line-height: 40px;
position: absolute;
text-align: center;
}
.wrapper {
width: 100%;
height: 100%;
overflow: auto;
min-height: 100%;
}
ul {
background: #333;
}
li {
height: 5vh;
color: #fff;
padding: 0 15px;
line-height: 5vh;
background: #333;
border-bottom: 1px solid #fff;
}
</style>
<!-- html -->
<div id="scroller" class="scroller">
<div class="refresh-text">正在刷新...</div>
<div class="wrapper"><ul></ul></div>
<div class="loading-text">正在加载...</div>
</div>
js
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
(function () {
var el; // wrapper element
var pos = null; // touch poistion
var dis = null; // tochmove offset
var offset = 40; // thie max offset
var wrapper = null; // content wrapper
var direction = null; // ['up', 'down']
var canTranslate = null; // can translate

var scrolled = null;
var maxScroll = null;
var scrollHeight = null;
var offsetHeight = null;

var data = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
];

/*
render数据
type<string>: ['refresh', 'loadMore']
data<array>: data
*/
var render = function (type, data) {
var ul = el.querySelector("ul");
if (type === "refresh") {
ul.innerHTML = "";
data.forEach(function (item, index) {
let li = document.createElement("li");
li.innerHTML = item;
ul.appendChild(li);
});
} else {
data.forEach(function (item, index) {
let li = document.createElement("li");
li.innerHTML = item;
ul.appendChild(li);
});
}
setTimeout(function () {
resetScroller();
}, 400);
};
/*
refresh
*/
var refresh = function () {
render("refresh", data);
};
/*
loadMore
*/
var loadMore = function () {
var _data = [];
var ul = el.querySelector("ul");
var _start = ul.querySelectorAll("li").length;
for (var i = 0; i < 10; i++) {
_data[i] = _start + i;
}
render("loadMore", _data);
};
/*
resetScroller
*/
var resetScroller = function () {
wrapper.style.transition = "all ease .4s";
wrapper.style.transform = "translateY(0)";
setTimeout(function () {
wrapper.style.transition = "";
}, 400);
};
/*
touchstart
*/
var touchstart = function (event) {
event.stopPropagation();
pos = event.touches[0].pageY;
// 需要判断wrapper是否在滚动过程中,如果是则不处理
scrolled = wrapper.scrollTop;
scrollHeight = wrapper.scrollHeight;
offsetHeight = wrapper.offsetHeight;
maxScroll = scrollHeight - offsetHeight;
if (scrolled === 0 || scrolled === maxScroll) {
canTranslate = true;
} else {
canTranslate = false;
}
};
/*
touchmove
*/
var touchmove = function (event) {
event.stopPropagation();
if (!canTranslate) return;
var _pos = event.touches[0].pageY;
var dis = _pos - pos;
if (dis > 40) dis = 40;
if (dis < -40) dis = -40;
direction = dis < 0 ? "up" : "down";
// 需要判断wrapper是否在滚动过程中,如果是则不处理
if (
(scrolled === 0 && direction === "down") ||
(scrolled === maxScroll && direction === "up")
) {
canTranslate = true;
} else {
canTranslate = false;
}
if (!canTranslate) return;

wrapper.style.transform = "translateY(" + dis + "px)";
};
/*
touchend
*/
var touchend = function (event) {
event.stopPropagation();
if (!canTranslate) return;
var _pos = event.changedTouches[0].pageY;
var _dis = _pos - pos;
pos = null;
dis = null;
direction = null;
if (_dis > 40) {
refresh();
} else if (_dis < -40) {
loadMore();
} else {
resetScroller();
}
};
/*
onload
*/
window.onload = function () {
el = document.querySelector("#scroller");
wrapper = el.querySelector(".wrapper");
render("refresh", data);
el.addEventListener("touchstart", touchstart, false);
el.addEventListener("touchmove", touchmove, false);
el.addEventListener("touchend", touchend, false);
};
})();

最后,个人感觉上拉加载更多换成滑动到底部自动加载体验应该会更好一些.

参考文章:H5 下拉刷新和上拉加载实现原理浅析

[越努力,越幸运!]