效果示例图
示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title></title>
<style type="text/css">
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.main {
width: 100%;
height: 100vh;
background-color: #f5f5f5;
position: relative;
}
.dot-wrap {
width: 100%;
height: 30px;
position: absolute;
background-color: #fff;
top: -30px;
}
.dot {
position: absolute;
width: 10px;
height: 10px;
border-radius: 10px;
background-color: rgb(0, 0, 0, 0.3);
top: 0;
left: 50%;
margin-left: -5px;
}
.dot:last-child {
display: none;
}
.dot.loading {
display: unset;
animation: dot-move 1.5s infinite;
}
@keyframes dot-move {
0% {
transform: translateX(-20px);
}
33.33% {
transform: translateX(-20px);
}
33.34% {
transform: translateX(0px);
}
66.66% {
transform: translateX(0px);
}
66.67% {
transform: translateX(20px);
}
100% {
transform: translateX(20px);
}
}
.block-item {
width: 100%;
height: 200px;
background-color: red;
margin-bottom: 12px;
}
</style>
</head>
<body>
<div class="main">
<div class="dot-wrap">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
<div class="block-item"></div>
</div>
</body>
<script type="text/javascript">
let timerHandle = null;
const mainDom = document.querySelector(".main");
const dots = document.querySelectorAll(".dot");
const rootDocument = document.documentElement;
//当滚动条在最顶部时可以下拉刷新
if (rootDocument.scrollTop === 0) {
addTouchEvent();
}
//滚动监听
window.onscroll = function() {
//当滚动条到达顶部时,可以触发下拉拖动事件
if (rootDocument.scrollTop <= 0) {
rootDocument.scrollTop = 0;
addTouchEvent();
} else {
removeTouchEvent();
}
}
let distance, ox, oy, x, y = 0;
function startEvent(e) {
console.log("[start]", e)
//获取手指起始值
ox = e.touches[0].clientX;
oy = e.touches[0].clientY;
}
function moveEvent(e) {
if (!e.cancelable) {
return; // 如果事件不可取消,直接返回,避免报错
}
//获取手指移动值
x = e.touches[0].clientX;
y = e.touches[0].clientY;
//判断下拉意图
if (y - oy > 0) {
const deg = Math.atan(Math.abs(x - ox) / Math.abs(y - oy)) / Math.PI * 180;
if (deg > 40) {
ox = x;
oy = y;
return false;
}
} else {
removeTouchEvent();
if (rootDocument.scrollTop === 0) {
addTouchEvent();
return false;
}
}
//手指移动的距离
distance = y - oy;
//添加阻尼效果
let percent = (100 - distance * 0.5) / 100;
percent = percent < 0.5 ? 0.5 : percent;
distance = distance * percent
//设置页面偏移距离
mainDom.style.transform = `translateY(${distance}px)`
console.log("[move]", distance)
if (distance > 20 && distance <= 50) {
dots[0].style.transform = `translateX(-${(distance-20)*2/3}px)`;
dots[2].style.transform = `translateX(${(distance-20)*2/3}px)`;
} else if (distance > 50) {
dots[0].style.transform = `translateX(-20px)`;
dots[2].style.transform = `translateX(20px)`;
}
e.preventDefault();
}
function endEvent() {
//当拖动的相对值大于50时
if (distance >= 50) {
//可以触发下拉刷新
dots[3].classList.add('loading')
mainDom.style.transition = `all 0.2s`;
mainDom.style.transform = `translateY(50px)`
if (timerHandle) {
clearTimeout(timerHandle)
}
timerHandle = setTimeout(() => {
if (timerHandle) {
clearTimeout(timerHandle)
}
removeEffect()
}, 2000);
} else {
removeEffect()
}
}
function removeEffect() {
//清除过渡效果
mainDom.style.transition = `all 0.2s`;
mainDom.style = '';
dots[3].classList.remove('loading')
}
function addTouchEvent() {
/**
* 通过将`passive`设置为`false`,表示在触发`touchmove`事件时,事件处理函数可以调用`preventDefault()`来阻止默认行为。
* 这意味着在移动过程中,可以阻止浏览器执行默认的滚动行为。
*/
mainDom.addEventListener('touchstart', startEvent, {
passive: false
});
mainDom.addEventListener("touchmove", moveEvent, {
passive: false
})
mainDom.addEventListener('touchend', endEvent, {
passive: false
})
}
function removeTouchEvent() {
mainDom.removeEventListener('touchstart', startEvent);
mainDom.removeEventListener("touchmove", moveEvent)
mainDom.removeEventListener('touchend', endEvent)
}
</script>
</html>