如何实现可视时触发SVG路径动画并锁定滚动至完成?
SVG路径动画:滚动触发+动画期间锁定滚动
解决步骤
1. 标记目标区域
给目标section添加ID,方便后续监听触发时机:
<section id="svg-animation-section" style="height: 150vh;"> <div id="svg-container2"> <svg viewBox="0 0 1440 320" style="transform: scaleX(-1)"> <path id="my-path-2" class="path-2" d="M0,256L48,229.3C96,203,192,149,288,133.3C384,117,480,139,576,176C672,213,768,267,864,266.7C960,267,1056,213,1152,181.3C1248,149,1344,139,1392,133.3L1440,128" /> </svg> </div> <svg viewBox="0 0 1440 320"> <path id="my-path" class="path-" d="M0,256L48,229.3C96,203,192,149,288,133.3C384,117,480,139,576,176C672,213,768,267,864,266.7C960,267,1056,213,1152,181.3C1248,149,1344,139,1392,133.3L1440,128" /> </svg> </section>
2. 调整CSS样式
添加滚动锁定类,同时重置路径初始显示状态:
svg { width: 100%; height: 30%; z-index: -1; } path { stroke: #0099ff; stroke-width: 2; fill: none; /* 初始隐藏路径,由JS控制绘制进度 */ stroke-dasharray: 0; stroke-dashoffset: 0; } /* 滚动锁定样式:禁止页面滚动 */ .scroll-locked { overflow: hidden; height: 100vh; }
3. JS实现监听与动画控制
用Intersection Observer精准监听section进入视口的时机,结合GSAP(或原生JS)控制路径动画,同时处理滚动锁定:
// 初始化路径长度 const path1 = document.querySelector("#my-path"); const pathLength1 = path1.getTotalLength(); path1.style.strokeDasharray = pathLength1; path1.style.strokeDashoffset = pathLength1; const path2 = document.querySelector("#my-path-2"); const pathLength2 = path2.getTotalLength(); path2.style.strokeDasharray = pathLength2; path2.style.strokeDashoffset = pathLength2; const section = document.querySelector("#svg-animation-section"); let isAnimating = false; // 滚动锁定/解锁函数 function lockScroll() { document.body.classList.add("scroll-locked"); } function unlockScroll() { document.body.classList.remove("scroll-locked"); } // 监听section进入视口的状态 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // 仅当section进入视口且无动画在执行时触发 if (entry.isIntersecting && !isAnimating) { isAnimating = true; lockScroll(); // --- GSAP动画方案(需引入GSAP库)--- gsap.timeline({ // 动画完成后解锁滚动 onComplete: () => { isAnimating = false; unlockScroll(); } }) // 绘制path1,时长2秒 .to(path1, { strokeDashoffset: 0, duration: 2, ease: "power2.inOut" }) // 延迟0.5秒启动path2绘制,形成交错效果 .to(path2, { strokeDashoffset: 0, duration: 2, ease: "power2.inOut" }, "-=1.5"); // --- 原生JS动画方案(无需额外库)--- // function animatePath(path, totalLength, duration) { // const startTime = performance.now(); // return new Promise(resolve => { // function updateFrame(currentTime) { // const elapsed = currentTime - startTime; // const progress = Math.min(elapsed / duration, 1); // // 更新路径绘制进度 // path.style.strokeDashoffset = totalLength * (1 - progress); // progress < 1 ? requestAnimationFrame(updateFrame) : resolve(); // } // requestAnimationFrame(updateFrame); // }); // } // // 并行执行两个路径动画,完成后解锁滚动 // Promise.all([ // animatePath(path1, pathLength1, 2000), // animatePath(path2, pathLength2, 2000) // ]).then(() => { // isAnimating = false; // unlockScroll(); // }); } }); }, { threshold: 0.1 }); // 当section进入视口10%时触发 observer.observe(section);
关键说明
- Intersection Observer:替代全局scroll监听,只有目标区域进入视口才触发动画,性能更优
- 滚动锁定:通过给body添加类实现,动画结束后自动移除类解锁滚动,避免用户干扰动画过程
- 动画选择:GSAP方案支持缓动函数和时间线控制,动画更顺滑;原生方案无需额外依赖,适合轻量场景
内容的提问来源于stack exchange,提问作者Agent
相关产品推荐
相关产品推荐

