这是手机端常见的一个功能,可能很多人都是用框架或者插件实现。
这里,我试着用原生js实现。
这样能更明白原理与底层实现
首先,布局,模拟初始数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Document</title>
<style>
body {
margin: 0;
}
html,
body {
height: 100%;
}
header,
footer {
width: 100%;
height: 40px;
position: absolute;
left: 0;
text-align: center;
line-height: 40px;
background: #999999;
color: #ffffff;
z-index: 999;
}
header {
top: 0;
}
footer {
bottom: 0;
}
ul {
display: block;
width: 100%;
position: absolute;
top: 40px;
bottom: 40px;
overflow: auto;
list-style: none;
padding: 0;
margin: 0;
}
ul>li {
width: 100%;
height: 40px;
line-height: 40px;
text-indent: 20px;
border-bottom: 1px solid #666666;
background: #ffffff;
color: #333333;
}
/* 下拉刷新的时候做 */
#loading{
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
color: #333333;
transition: all 0.5s;
position: absolute;
z-index: 1;
color: #ffffff;
background: orange;
top: 0;
}
</style>
</head>
<body>
<header>
我是头部
</header>
<section id="con">
<div id="loading">加载中......</div>
<ul id="list">
</ul>
</section>
<div id="loadEnd">已加载全部数据</div>
<footer>
我是尾部
</footer>
</body>
<script>
<script>
//获取数据
var list = document.getElementById("list");
function getData() {
var html = '';
for (var i = 0; i < 20; i++) {
html += '<li>我是第' + (i + 1) + '个li</li>';
}
list.innerHTML = html;
}
//初始加载函数
window.onload = () => {
//初始请求数据
getData();
}
</script>
</script>
</html>
会得到这样一个网页,头部底部固定,中间部分可滑动
接下来,我们来监听ul的滚动事件
list.addEventListener("scroll", function () {
//这里可以获取到ul距离屏幕顶部的距离,每次滚动都会刷新
console.log(this.scrollTop);
})
来做一个分析,接下来不要着急写代码
看到这个图,我们就知道要做什么了
//ul的高度 不变的 定死的
let listH = list.clientHeight;
//所有li总高度
let contentH = this.childNodes.length * 41;
//差值
let diffValue = contentH - listH;
//距离视窗还有50的时候,开始触发;
if (this.scrollTop + 50 >= diffValue) {
console.log('该加载了...')
getData();
}
上滑加载完美实现,当我滑到快到最后一个li的时候,触发获取数据的方法
我们再添加一个节流阀,不让它无限加载。
function getData() {
var html = '';
for (var i = 0; i < 20; i++) {
html += '<li>我是第' + (i + 1) + '个li</li>';
}
var length = list.children.length;
if (length === 0) {
list.innerHTML = html;
} else if(length > 0 && length < 100){
//html是字符串
var newHtml = parseDom(html);
//后面插入元素
insertAfter(newHtml, list.children[length - 1]);
}else if(length === 100){
console.log("已经到底了,别拉了");
}
}
这里有两个非常重要的方法,都是原生js操作
1.字符串dom化
//字符串dom化
function parseDom(arg) {
var objEle = document.createElement("div");
objEle.innerHTML = arg;
return [...objEle.childNodes];
};
2.在已有元素后面插入元素
//在已有元素后面插入元素
function insertAfter(newElement, targetElement) {
newElement.forEach(element => {
//在后面插入元素 after:js新的dom api
targetElement.after(element)
});
return
}
下拉加载
通过判断ul的scrollTop值,当ul的scrollTop === 0的时候,触发
添加到监听滚动事件里,加一些样式操作即可
有些许粗糙,功能为主,见谅见谅
if(this.scrollTop === 0){
list.style.top = "80px";
loading.style.top = "40px";
//刷新数据
setTimeout(()=>{
loading.style.top = "0";
list.style.top = "40px";
},1000)
}
那么完整代码就是
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Document</title>
<style>
body {
margin: 0;
}
html,
body {
height: 100%;
}
header,
footer {
width: 100%;
height: 40px;
position: absolute;
left: 0;
text-align: center;
line-height: 40px;
background: #999999;
color: #ffffff;
z-index: 999;
}
header {
top: 0;
}
footer {
bottom: 0;
}
ul {
display: block;
width: 100%;
position: absolute;
top: 40px;
bottom: 40px;
overflow: auto;
list-style: none;
padding: 0;
margin: 0;
}
ul>li {
width: 100%;
height: 40px;
line-height: 40px;
text-indent: 20px;
border-bottom: 1px solid #666666;
background: #ffffff;
color: #333333;
}
/* 下拉刷新的时候做 */
#loading,#loadEnd{
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
color: #333333;
transition: all 0.5s;
position: absolute;
z-index: 1;
color: #ffffff;
}
#loading{
background: orange;
top: 0;
}
#loadEnd{
background: green;
bottom: 0;
}
</style>
</head>
<body>
<header>
我是头部
</header>
<section id="con">
<div id="loading">加载中......</div>
<ul id="list">
</ul>
</section>
<div id="loadEnd">已加载全部数据</div>
<footer>
我是尾部
</footer>
<script>
//获取数据
var list = document.getElementById("list");
var loading = document.getElementById("loading");
var loadEnd = document.getElementById("loadEnd");
function getData() {
var html = '';
for (var i = 0; i < 20; i++) {
html += '<li>我是第' + (i + 1) + '个li</li>';
}
var length = list.children.length;
if (length === 0) {
list.innerHTML = html;
} else if(length > 0 && length < 100){
//html是字符串
var newHtml = parseDom(html);
//后面插入元素
insertAfter(newHtml, list.children[length - 1]);
}else if(length === 100){
console.log("已经到底了,别拉了");
list.style.bottom = "80px";
loadEnd.style.bottom = "40px";
//加个定时器模拟接口请求结束 隐藏掉此条
//或者可以插入一条元素
}
}
//字符串dom化
function parseDom(arg) {
var objEle = document.createElement("div");
objEle.innerHTML = arg;
return [...objEle.childNodes];
};
//在已有元素后面插入元素
function insertAfter(newElement, targetElement) {
newElement.forEach(element => {
//在后面插入元素 js 新的dom api
targetElement.after(element)
});
return
}
//初始加载函数
window.onload = () => {
//初始请求数据
getData();
list.addEventListener("scroll", function () {
//ul的高度 不变的 定死的
let listH = list.clientHeight;
//所有li总高度
let contentH = this.childNodes.length * 41;
//下拉刷新
if(this.scrollTop === 0){
list.style.top = "80px";
loading.style.top = "40px";
//刷新数据
setTimeout(()=>{
loading.style.top = "0";
list.style.top = "40px";
},1000)
}
//距离
let diffValue = contentH - listH;
//ul离顶部的距离
//距离视窗还有50的时候,开始触发;
if (this.scrollTop + 50 >= diffValue) {
console.log('该加载了...')
getData();
}
})
}
</script>
</body>
</html>
此篇文章为作者原创
如需转载 请注明出处