<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>Pull to Refresh</title>
<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>
<script>
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.onmousewheel = 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.onload = ()=>{
fullData(5, 0);
const scrollContainer = document.querySelector('.scroll-container');
new PullToRefresh(scrollContainer, (type)=>fullData(5, type));
}
</script>
</head>
<body>
<div class="scroll-container"><ul></ul></div>
</body>
</html>
JavaScript 下拉/上拉刷新
最新推荐文章于 2024-05-22 18:38:38 发布