实现SVG路径动画随页面滚动触发(无需jQuery)
实现SVG路径滚动触发动画(原生JS)
问题
当前SVG路径动画在页面加载时自动完成,需要改为滚动到SVG所在区域时才触发动画,要求用原生JavaScript实现,不引入任何额外库。
解决步骤
1. 调整CSS结构
先移除原来直接绑定在.st0、.st1上的自动动画,把动画逻辑放到单独的类中,只有当元素添加这个类时才会启动动画:
/* 基础样式保留,移除自动动画 */ .st0, .st1{ fill:none; stroke:#000000; stroke-miterlimit:10; stroke-dasharray: 1000; stroke-dashoffset: 1000; } /* 动画类,需要时才添加 */ .animate-path { -webkit-animation: draw1 4s linear forwards; animation: draw1 4s linear forwards; } /* 动画关键帧保留 */ @-webkit-keyframes draw1{ to {stroke-dashoffset: 0;} } @keyframes draw1{ to {stroke-dashoffset: 0;} } @-webkit-keyframes draw2{ to {stroke-dashoffset: 0;} } @keyframes draw2{ to {stroke-dashoffset: 0;} }
2. 添加原生JavaScript监听逻辑
这段代码监听页面滚动,判断SVG是否进入视口,一旦进入就给所有路径添加动画类,且只执行一次:
// 获取SVG元素 const svgElement = document.querySelector('svg'); // 获取所有需要动画的路径元素 const pathElements = document.querySelectorAll('.st0, .st1'); // 标记动画是否已触发 let animationTriggered = false; // 判断元素是否在视口内的函数 function isInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top <= window.innerHeight && rect.bottom >= 0 ); } // 滚动监听函数 function checkScroll() { if (!animationTriggered && isInViewport(svgElement)) { // 给所有路径添加动画类 pathElements.forEach(el => el.classList.add('animate-path')); animationTriggered = true; // 动画触发后移除监听,优化性能 window.removeEventListener('scroll', checkScroll); } } // 初始化监听 window.addEventListener('scroll', checkScroll); // 页面加载时先检查一次,避免SVG一开始就在视口内的情况 checkScroll();
3. 完整HTML结构
保留原SVG代码,确保路径类仍为.st0和.st1即可:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 1514.85 819.06" style="enable-background:new 0 0 1514.85 819.06;" xml:space="preserve" > <style type="text/css"> .st0{fill:none;stroke:#58595B;stroke-width:2;stroke-miterlimit:10;} .st1{fill:none;stroke:#7F8183;stroke-width:2;stroke-miterlimit:10;} .st2{fill:#7E8183;} .st3{font-family:'Tahoma';} .st4{font-size:27px;} .st5{fill:#7E8183;stroke:#7E8183;stroke-width:0.09;stroke-miterlimit:10;} .st6{fill:#FFFFFF;} .st7{fill:none;stroke:#7E8183;stroke-width:2;stroke-miterlimit:10;} .st8{fill:#7E8183;stroke:#FFFFFF;stroke-miterlimit:10;} .st9{fill:#7E8183;stroke:#FFFFFF;stroke-width:1.6;stroke-miterlimit:10;} .st10{fill:#7E8183;stroke:#FFFFFF;stroke-width:0.2174;stroke-miterlimit:10;} </style> <g id="Layer_1"> <polyline class="st0" points="567.16,290.57 402.56,290.57 402.56,193.38 "/> </g> <g id="Layer_2"> <polyline class="st0" points="567.16,373.55 137.02,373.55 137.02,193.38 "/> </g> <g id="Layer_3"> <polyline class="st0" points="567.16,455.77 139.01,455.77 139.01,636.41 "/> </g> <g id="Layer_4"> <polyline class="st0" points="567.16,539.21 402.56,539.21 402.56,636.41 "/> </g> <g id="Layer_5"> <polyline class="st1" points="991.61,290.57 1156.21,290.57 1156.21,193.38 "/> </g> <g id="Layer_6"> <polyline class="st1" points="991.61,373.55 1419.66,373.55 1419.66,193.38 "/> </g> <g id="Layer_7"> <polyline class="st1" points="991.61,455.77 1419.66,455.77 1419.66,636.41 "/> </g> <g id="Layer_8"> <polyline class="st1" points="991.61,539.21 1156.21,539.21 1156.21,636.41 "/> </g> </svg>
说明
- 动画只会触发一次,避免滚动时重复执行
- 页面加载时会先检查一次,如果SVG一开始就在视口内,会直接启动动画
- 用
getBoundingClientRect()判断元素是否在视口,是原生JS的可靠方法 - 动画触发后移除滚动监听,减少性能消耗
内容的提问来源于stack exchange,提问作者Emirhan
相关产品推荐
相关产品推荐

