<!DOCTYPE html>
<html lang=\"zh-cn\">
<head>
< charset=\"UTF-8\">
< >Pull to Refresh</ >
<style>
* {
margin: 0;
padding: 0;
}
.scroll-container {
position: relative;
/** 拖动到最下面的时候滚动条会突然消失,造成页面resize,所以通过overflow隐藏滚动条 */
overflow-y: hidden;
/** height不能设置为100%,因为它是根据内容而定的,而100vh表示浏览器满高度 */
height: 100vh;
}
.scroll-container>ul {
list-style: none;
text-align: center;
line-height: 300%;
color: white;
position: absolute;
width: 100%;
background-color: #999;
}
.scroll-container>ul>li {
border: 1px solid white;
}
.scroll-container>div:first-child, .scroll-container>div:last-child {
justify-content: center;
align-items: center;
color: black;
background-color: red;
position: absolute;
/** absolute的元素,如果不设置宽度,即使是block的也会变成wrap_content */
width: 100%;
overflow-y: hidden;
}
</style>
< >
function fullData(count, type) {
console.log(\"refreshType: \" + type);
const container = document.querySelector(\".scroll-container>ul\");
for(let i=0; i<count; i++) {
const node = document.createElement(\"li\");
node.textContent = \"第 \" + container.children.length + \" 条测试数据\";
container.appendChild(node);
}
}
class PullToRefresh {
constructor(scrollContainer, callback) {
const container = scrollContainer.firstElementChild;
const contentBefore = document.createElement(\"div\");
const contentEnd = document.createElement(\"div\");
scrollContainer.insertBefore(contentBefore, scrollContainer.firstChild);
scrollContainer.appendChild(contentEnd);
this.container = container;
container.tips = [\"Pull Down To Refresh\", \"Pull Up To Refresh\", \"Release To Refresh\", \"Loading...\", \"All Data Has Been Loaded\"];
//拉伸出多大的空间说明刷新有效
container.effectDistance = 80;
//拉伸出的空间的极限值
container.tensileLimit = 100;
//0表示不刷新,1表示下拉刷新,2表示上拉刷新
container.refreshType = 0;
//每次滚动的距离
container.scrollStep = 20;
container.pullToRefreshCallback = callback;
container.siblingPrev = contentBefore;
container.siblingNext = contentEnd;
this.setListener(container);
}
setListener(container) {
container.addEventListener(\'touchstart\', this.touchStart, false);
container.addEventListener(\'touchmove\', this.touchMove, false);
container.addEventListener(\'touchend\', this.touchEndFunc, false);
container.addEventListener(\'mousedown\', this.touchStart, false);
container.addEventListener(\'mousemove\', this.touchMove, false);
container.addEventListener(\'mouseup\', this.touchEnd, false);
//火狐使用DOMMouseScroll,其它浏览器使用mousewheel事件
container.addEventListener(\"DOMMouseScroll\", this.scroll, false);
container. = this.scroll;
}
touchStart(event) {
/*
event.button
其它浏览器:0鼠标左键;1鼠标中键;2鼠标右键
IE浏览器: 1鼠标左键;4鼠标中键;2鼠标右键
*/
if(event.button === 0) {
const container = event.currentTarget;
container.isTouch = true;
container.startY = event.y;
container.startTop = container.offsetTop;
container.refreshType = 0;
}
}
touchMove(event) {
const container = event.currentTarget;
if(event.button === 0 && container.isTouch) {
//从鼠标左键按下的点开始计算的下拉的距离
const diff = event.y - container.startY;
//容器与页面左上角的相对位移
const containerTop = container.startTop + diff;
if(diff > 0) {
//下拉
if(containerTop > container.tensileLimit) {
return;
} else if(containerTop > container.effectDistance) {
container.siblingPrev.textContent = container.tips[2];
container.siblingPrev.style.height = containerTop + \"px\";
container.refreshType = 1;
} else if(containerTop > 0) {
container.siblingPrev.textContent = container.tips[0];
container.siblingPrev.style.display = \"flex\";
container.siblingPrev.style.height = containerTop + \"px\";
container.refreshType = 0;
} else {
container.siblingPrev.style.display = \"none\";
container.refreshType = 0;
}
container.style.top = containerTop + \"px\";
container.siblingNext.style.display = \"none\";
} else {
//上拉
/*
container.clientHeight这个是容器完整的高度(包括不可见部分)
document.documentElement.clientHeight这个是窗口实际高度
*/
//超出屏幕可见区域的高度值(正数)
const exceedHeight = container.clientHeight - document.documentElement.clientHeight;
//下面这个逻辑有点复杂,可以先分开写,然后寻找共同点并合并
/*
if(exceedHeight < 0) {
//小于0表示内容未填满整个窗口
if(containerTop + container.tensileLimit < 0) {
return;
} else if(containerTop + container.effectDistance < 0) {
container.siblingNext.textContent = container.tips[2];
container.siblingNext.style.height = -containerTop + \"px\";
container.siblingNext.style.top = containerTop + container.clientHeight + \"px\";
container.refreshType = 2;
} else if(containerTop < 0) {
container.siblingNext.textContent = container.tips[1];
container.siblingNext.style.display = \"flex\";
container.siblingNext.style.height = -containerTop + \"px\";
container.siblingNext.style.top = containerTop + container.clientHeight + \"px\";
container.refreshType = 0;
} else {
container.siblingNext.style.display = \"none\";
container.refreshType = 0;
}
} else {
if(containerTop + exceedHeight + container.tensileLimit < 0) {
return;
} else if(containerTop + exceedHeight + container.effectDistance < 0) {
container.siblingNext.textContent = container.tips[2];
container.siblingNext.style.height = containerTop + exceedHeight + \"px\";
container.siblingNext.style.top = containerTop + container.clientHeight + \"px\";
container.refreshType = 2;
} else if(containerTop + exceedHeight < 0) {
container.siblingNext.textContent = container.tips[1];
container.siblingNext.style.display = \"flex\";
container.siblingNext.style.height = containerTop + exceedHeight + \"px\";
container.siblingNext.style.top = containerTop + container.clientHeight + \"px\";
container.refreshType = 0;
} else {
container.siblingNext.style.display = \"none\";
container.refreshType = 0;
}
}
*/
const tmpExceedHeight = exceedHeight < 0 ? 0 : exceedHeight;
if(containerTop + tmpExceedHeight + container.tensileLimit < 0) {
return;
} else if(containerTop + tmpExceedHeight + container.effectDistance < 0) {
container.siblingNext.textContent = container.tips[2];
container.siblingNext.style.height = -containerTop - exceedHeight + \"px\";
container.siblingNext.style.top = containerTop + container.clientHeight + \"px\";
container.refreshType = 2;
} else if(containerTop + tmpExceedHeight < 0) {
container.siblingNext.textContent = container.tips[1];
container.siblingNext.style.display = \"flex\";
container.siblingNext.style.height = -containerTop - exceedHeight + \"px\";
container.siblingNext.style.top = containerTop + container.clientHeight + \"px\";
container.refreshType = 0;
} else {
container.siblingNext.style.display = \"none\";
container.refreshType = 0;
}
container.style.top = containerTop + \"px\";
container.siblingPrev.style.display = \"none\";
}
}
}
touchEnd(event) {
if(event.button == 0) {
const container = event.currentTarget;
container.isTouch = false;
if(container.offsetTop > 0) {
container.style.top = \"0\";
} else {
const containerTop = container.clientHeight - document.documentElement.clientHeight;
if(containerTop < 0) {
//内容未填满整个窗口
container.style.top = \"0\";
} else if(container.offsetTop + containerTop < 0) {
container.style.top = -containerTop + \"px\";
}
}
container.siblingPrev.style.display = \"none\";
container.siblingNext.style.display = \"none\";
if(container.refreshType != 0) {
container.pullToRefreshCallback(container.refreshType);
}
}
}
scroll(event) {
const container = event.currentTarget;
const containerTop = container.clientHeight - document.documentElement.clientHeight;
if(containerTop < 0 || container.isTouch) {
//小于0表示内容未填满整个窗口
return;
}
const minTop = document.documentElement.clientHeight - container.clientHeight;
let top = 0;
//firefox用的是event.detail,+3表示为向下滚动,-3表示向上滚动;其它浏览器用的是wheelDelta,+120表示向上,-120表示向下
if((event.detail && event.detail > 0) || (event.wheelDelta && event.wheelDelta < 0)) {
top = container.offsetTop - container.scrollStep;
} else {
top = container.offsetTop + container.scrollStep;
}
top = Math.min(0, Math.max(minTop, top));
container.style.top = top + \"px\";
}
}
window. = ()=>{
fullData(5, 0);
const scrollContainer = document.querySelector(\'.scroll-container\');
new PullToRefresh(scrollContainer, (type)=>fullData(5, type));
}
</ >
</head>
<body>
<div class=\"scroll-container\"><ul></ul></div>
</body>
</html>
继续阅读与本文标签相同的文章
上一篇 :
自然语言处理中的注意力机制是干什么的?
下一篇 :
矢量和矩阵的相关方法插件
-
登榜!风采依旧表现“佳”
2026-05-18栏目: 教程
-
苹果新获专利详细介绍了Measure如何利用AR进行精确视觉测量
2026-05-18栏目: 教程
-
消费升级不是把原来的成熟产品卖得更高更贵
2026-05-18栏目: 教程
-
红旗首款纯电SUV登场!动力强续航足,这外观太漂亮!
2026-05-18栏目: 教程
-
互联网时代,挑战与机遇并存
2026-05-18栏目: 教程
