JS+CSS 更完美展现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>跳动加载指示器</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
margin: 0;
}
.content {
height: 1000px;
background-color: #f4f4f4;
text-align: center;
padding: 20px;
}
.box {
display: block;
width: 300px;
height: 150px;
margin: 50px auto;
background-color: lightcoral;
color: white;
text-align: center;
line-height: 150px;
font-size: 20px;
border-radius: 8px;
opacity: 1; /* 初始时不可见 */
transform: translateY(50px); /* 初始位置偏移 */
transition: all 1s ease-out;
}
/* 定义出现动画 */
@keyframes fadeInUp {
0% {
opacity: 0;
transform: translateY(50px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.show {
animation: fadeInUp 1s ease-out forwards;
}
</style>
</head>
<body>
<div class="box"style="height: 300px; background-color: lightblue; margin-top: 500px;">这是第一个 DIV</div>
<div class="box">这是第二个 DIV</div>
<div class="box"style="height: 300px; background-color: lightblue; margin-top: 500px;">这是第三个 DIV</div>
<div class="box">这是第四个 DIV</div>
<div class="box">这是第一个 DIV</div>
<div class="box"style="height: 300px; background-color: lightblue; margin-top: 500px;">这是第5个 DIV</div>
<div class="box">这是第三个 DIV</div>
<div class="box"style="height: 300px; background-color: lightblue; margin-top: 500px;">这是第三88个 DIV</div>
<div class="box">这是第一个 DIV</div>
<div class="box">这是第二个 DIV</div>
<div class="box">这是第三个 DIV</div>
<div class="box">这是第四个 DIV</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
const divs = document.querySelectorAll('div'); // 选择所有 div 元素
// 创建一个 IntersectionObserver
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) { // 当元素进入视口时
entry.target.classList.add('show'); // 给元素添加动画类
observer.unobserve(entry.target); // 只执行一次,移除监听
}
});
}, {
threshold: 0.1 // 只有当元素至少 10% 进入视口时才触发
});
// 为每个 div 元素添加观察
divs.forEach(div => observer.observe(div));
});
</script>
</body>
</html>
-
HTML:
- 页面上有几个
.box
元素。它们默认是不可见的,只有当它们滚动到视口时,才会触发动画。
- 页面上有几个
-
CSS:
.box
元素初始状态为opacity: 0
(不可见)和transform: translateY(50px)
(位置偏移)。这意味着元素从下方滑动到页面上。@keyframes fadeInUp
动画定义了元素从不可见状态到可见状态,并从下方滑动到其原位置。.show
类会应用这个动画。
-
JavaScript:
getBoundingClientRect()
用于获取元素相对于视口的位置。通过检查boxTop
的值与windowHeight
(窗口高度)来确定元素是否已经进入视口。if (boxTop < windowHeight - 100)
检查当前元素距离视口顶部的距离。如果元素离视口顶部足够近(100px以内),就触发动画。- 在滚动事件触发时,调用
checkScroll()
来检查每个元素是否进入视口。 checkScroll()
在页面加载时也会执行一次,确保当页面刷新时,如果某些元素已经在视口内,它们能立即显示动画。
- 使用
IntersectionObserver
:这是一个更现代和高效的方法,可以用来检测元素是否进入视口。它比滚动事件更高效,避免了反复计算和检查。
进一步优化:每一次载入后就继续载入动画,效果更加动感
结果:
- 每当
div
元素滚动到视口时,它都会触发动画,从下方滑动并渐显,完成一次动画。 - 如果用户滚动元素离开视口,动画会被移除,当元素再次进入视口时,动画会重新触发。
优点:
- 多次触发 :每次
div
元素进入视口时都会触发动画,无论之前是否已经显示过。 - 流畅的体验:适合需要持续响应用户滚动的动画效果,尤其适用于长页面和多个动画元素。
<script>
document.addEventListener("DOMContentLoaded", function() {
const divs = document.querySelectorAll('div'); // 选择所有 div 元素
// 创建一个 IntersectionObserver
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) { // 当元素进入视口时
entry.target.classList.add('show'); // 给元素添加动画类
} else {
entry.target.classList.remove('show'); // 离开视口时移除动画类
}
});
}, {
threshold: 0.1 // 只有当元素至少 10% 进入视口时才触发
});
// 为每个 div 元素添加观察
divs.forEach(div => observer.observe(div));
});
</script>