// 定义常量 DISTANCE 和 DURATION,分别表示元素距离视口的距离和动画的持续时间
const DISTANCE = 150;
const DURATION = 500;
// 创建一个 WeakMap 对象,用于存储元素和其对应的动画实例
const map = new WeakMap();
// 创建一个 IntersectionObserver 实例,用于观察元素是否与视口相交
const ob = new IntersectionObserver((entries) => {
// 遍历所有相交的元素
for (const entry of entries) {
// 如果元素与视口相交
if (entry.isIntersecting) {
// 获取元素对应的动画实例
const animation = map.get(entry.target);
if (animation) {
// 如果存在动画实例,则播放动画,并取消对该元素的观察
animation.play();
ob.unobserve(entry.target);
}
}
}
});
// 定义一个函数,用于判断元素是否在视口下方
function isBelowViewport(el) {
// 获取元素的矩形信息(位置、大小等)
const rect = el.getBoundingClientRect();
// 如果元素距离视口的距离大于视口高度,返回 true
return rect.top - DISTANCE > window.innerHeight;
}
// 导出一个 Vue 组件对象,包含 mounted 和 unmounted 生命周期钩子函数
export default {
mounted(el) {
// 如果元素不在视口下方,直接返回,不执行后续操作
if (!isBelowViewport(el)) {
return;
}
// 创建一个动画实例,描述一个元素的平移和透明度变化过程
const animation = el.animate([
{
transform: `translateY(${DISTANCE}px)`, // 初始状态:向下平移 DISTANCE 像素,透明度为0.5
opacity: 0.5
},
{
transform: `translateY(0)`, // 结束状态:回到原位,透明度为1
opacity: 1
}
], {
duration: DURATION, // 动画持续时间 DURATION
easing: 'ease-in-out', // 动画的速度曲线为 ease-in-out(先慢后快再慢)
fill: 'forwards' // 动画结束后,元素保持最后一帧的状态(而不是过渡到初始状态)
})
// 暂停动画,等待与视口相交时再播放
animation.pause();
// 开始观察元素与视口的相交情况,并存储该元素和其对应的动画实例到 map 中
ob.observe(el);
map.set(el, animation);
},
unmounted(el) {
// 组件卸载时,取消对元素的观察,并从 map 中移除该元素和其对应的动画实例
ob.unobserve(el);
},
}
Vue 组件,页面向下滚动元素在视口下方时的动画效果
最新推荐文章于 2024-03-24 09:50:04 发布