如何实现动画进入视口时仅触发启动一次?
实现元素进入视口时触发单次动画
我来帮你搞定这个需求——让.monster的精灵图动画只在元素进入视口时播放一次,而不是页面加载就自动执行。咱们分步骤来实现:
1. 重构CSS样式
先把动画相关的逻辑抽成独立的类,默认不给.monster加动画,这样页面加载时元素不会动:
/* 基础样式:仅定义元素外观,不包含动画 */ .monster { width: 200px; height: 200px; margin: -50px auto; background: url('/wp-content/uploads/2021/07/sprite1.png') left center; } /* 动画触发类:仅当元素进入视口时才添加 */ .monster-animate { animation: play 2.8s steps(15); animation-iteration-count: 1; /* 让动画结束后停在最后一帧,不跳回初始状态 */ animation-fill-mode: forwards; } @keyframes play { 100% { background-position: -3000px; } }
2. 用Intersection Observer监听视口
现代浏览器推荐用Intersection Observer API来检测元素是否进入视口,性能比scroll事件好太多,而且能精准控制触发时机:
// 获取目标元素 const monsterEl = document.querySelector('.monster'); // 创建观察者实例 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // 当元素进入视口时触发 if (entry.isIntersecting) { // 添加动画类 monsterEl.classList.add('monster-animate'); // 停止监听,确保动画只执行一次 observer.unobserve(monsterEl); } }); }, { // 可选:设置触发阈值,比如元素完全进入视口才触发(值0~1) threshold: 1.0 }); // 开始监听目标元素 observer.observe(monsterEl);
兼容旧浏览器的回退方案(可选)
如果需要兼容IE这类不支持Intersection Observer的浏览器,可以用scroll事件替代(注意性能略差):
const monsterEl = document.querySelector('.monster'); let animationTriggered = false; function checkViewportStatus() { if (animationTriggered) return; // 已经执行过动画就直接返回 const rect = monsterEl.getBoundingClientRect(); // 判断元素是否进入视口范围 const isVisible = rect.top < window.innerHeight && rect.bottom > 0; if (isVisible) { monsterEl.classList.add('monster-animate'); animationTriggered = true; // 移除scroll监听,避免后续重复触发 window.removeEventListener('scroll', checkViewportStatus); } } // 初始化时先检查一次(如果元素一开始就在视口内) checkViewportStatus(); // 添加滚动监听 window.addEventListener('scroll', checkViewportStatus);
这样调整后,你的精灵图动画就只会在.monster元素进入视口时播放一次,完美符合需求~
内容的提问来源于stack exchange,提问作者Matt Partridge
相关产品推荐
相关产品推荐

