通过 ScrollTrigger 来控制路径和背景图动画的触发与回退

1、SVG路径动画:通过修改 SVG 路径的 strokeDasharray 和 strokeDashoffset 属性,实现路径逐渐绘制出来的效果。

 2、背景图缩放:在滚动触发时,背景图会根据路径的动画进度进行缩放,从而实现平滑的视觉效果。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .mx-auto {
            margin-left: auto;
            margin-right: auto
        }
        .overflow-hidden {
            overflow: hidden
        }
        .absolute {
            position: absolute
        }
        .relative {
            position: relative
        }
        .left-0 {
            left: 0
        }
        .top-0 {
            top: 0
        }
        .right-0 {
            right: 0
        }
        .text-\[\#000\] {
            --tw-text-opacity: 1;
            color: rgba(0, 0, 0, var(--tw-text-opacity))
        }
        .w-full {
            width: 100%
        }
        .z-2 {
            z-index: 2
        }
        .z-3 {
            z-index: 3
        }
        @media (min-width: 650px) and (max-width:1023px) {
            .pad\:h-232px {
                height: 232px
            }
            .pad\:py-128rpx {
                padding-bottom: calc(var(--rpx, 1px)*128);
                padding-top: calc(var(--rpx, 1px)*128)
            }
            .pad\:text-center {
                text-align: center
            }
            .pad\:w-232px {
                width: 232px
            }
            .pad\:w-126\.26px {
                width: 126.26px
            }
            .pad\:w-720rpx {
                width: -webkit-calc(var(--rpx, 1px)*720);
                width: -moz-calc(var(--rpx, 1px)*720);
                width: calc(var(--rpx, 1px)*720)
            }
        }

        @media (min-width: 1024px) {
            .pc\:h-452px {
                height: 452px
            }
            .pc\:py-239rpx {
                padding-bottom: 239px;
                padding-top: 239px
            }
            .pc\:text-center {
                text-align: center
            }
            .pc\:w-452px {
                width: 452px
            }
            .pc\:w-246px {
                width: 246px
            }
            .pc\:w-1312rpx {
                width: -webkit-calc(var(--rpx, 1px)*1312);
                width: -moz-calc(var(--rpx, 1px)*1312);
                width: calc(var(--rpx, 1px)*1312)
            }
        }

        @media (max-width: 649px) {
            .mo\:h-232px {
                height: 232px
            }
            .mo\:py-100rpx {
                padding-bottom: calc(var(--rpx, 1px)*100);
                padding-top: calc(var(--rpx, 1px)*100)
            }
            .mo\:text-center {
                text-align: center
            }
            .mo\:w-232px {
                width: 232px
            }
            .mo\:w-126\.26px {
                width: 126.26px
            }
            .mo\:w-328rpx {
                width: -webkit-calc(var(--rpx, 1px)*328);
                width: -moz-calc(var(--rpx, 1px)*328);
                width: calc(var(--rpx, 1px)*328)
            }

        }

        @media (min-width: 1024px) {
            .pct\:text-72px {
                font-size: 72px;
                line-height: 1
            }
            .pct\:leading-\[86px\] {
                line-height: 86px
            }
        }

        @media (max-width: 1023px) {
            .svg-path {
                stroke-dasharray: 710;
                stroke-dashoffset: 710
            }
            .mot\:text-44px {
                font-size: 44px;
                line-height: 1
            }
            .mot\:leading-\[52px\] {
                line-height: 52px
            }
            .mot\:text-center {
                text-align: center
            }
        }

        @media (min-width: 1024px) {
            .svg-path {
                stroke-dasharray: 710;
                stroke-dashoffset: 710
            }
        }
        .abs-center {
            left: 50%;
            top: 50%;
            -webkit-transform: translateX(-50%) translateY(-50%);
            -moz-transform: translateX(-50%) translateY(-50%);
            -ms-transform: translateX(-50%) translateY(-50%);
            transform: translate(-50%) translateY(-50%)
        }
        .bg-img {
            -o-object-fit: cover;
            object-fit: cover;
            height: 100%;
            left: 0;
            position: absolute;
            top: 0;
            width: 100%;
        }
        .svg-path {
            stroke-dasharray: 700;
            stroke-dashoffset: 700
        }
    </style>
</head>

<body>
    <div style="height: 100vh; width: 100%;background-color: aqua;"></div>
    <div class="relative w-full z-2 overflow-hidden" ani-ksp-title="">
        <!-- 容纳SVG路径和背景图 -->
        <div class="absolute abs-center pc:w-452px pc:h-452px mo:w-232px mo:h-232px pad:w-232px pad:h-232px">
            <div class="bg-img" svg-group="" style="transform: scale(1);">
                <div class="bg-img">
                     <!-- 第一条SVG路径 -->
                    <svg
                    class="absolute right-0 top-0 pc:w-246px pc:h-452px mo:w-126.26px mo:h-232px pad:w-126.26px pad:h-232px"
                    width="246" height="452" viewBox="0 0 246 452" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path class="svg-path svg-path-1"
                        d="M20 20C42.2218 20 63.6235 23.5222 83.6741 30.0305C104.456 36.7805 123.791 46.7426 141.092 59.3332C158.672 72.1236 174.149 87.6319 186.908 105.238C199.383 122.449 209.261 141.674 215.969 162.324C222.483 182.374 226 203.776 226 225.997C226 248.224 222.483 269.62 215.969 289.676C209.219 310.457 199.257 329.793 186.666 347.093C173.876 364.673 158.367 380.15 140.761 392.909C123.549 405.384 104.324 415.262 83.6741 421.97C63.6235 428.483 42.2271 432 20 432"
                        stroke="url(#paint0_linear_1778_16707)" stroke-width="40" stroke-miterlimit="10"
                        stroke-linecap="round" style="stroke-dashoffset: 710px; stroke-width: 40;"></path>
                    <defs>
                        <linearGradient id="paint0_linear_1778_16707" x1="19.9972" y1="432" x2="19.9972" y2="20"
                            gradientUnits="userSpaceOnUse" class="">
                            <stop stop-color="#ff0000" class=""></stop>
                            <stop offset="1" stop-color="#c67d7d" class=""></stop>
                        </linearGradient>
                    </defs>
                </svg>
                </div>
                <!-- 第二条SVG路径 -->
                <svg
                    class="absolute left-0 top-0 pc:w-246px pc:h-452px mo:w-126.26px mo:h-232px pad:w-126.26px pad:h-232px"
                    width="246" height="452" viewBox="0 0 246 452" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path class="svg-path svg-path-2"
                        d="M226 432C203.779 432 182.378 428.483 162.327 421.97C141.678 415.262 122.453 405.384 105.242 392.909C87.6363 380.15 72.1282 364.673 59.338 347.093C46.7475 329.792 36.7855 310.457 30.0356 289.676C23.5169 269.626 20 248.224 20 226.003C20 203.781 23.5169 182.38 30.0303 162.329C36.7382 141.68 46.6161 122.455 59.0909 105.243C71.8496 87.6371 87.3261 72.1289 104.905 59.3385C122.206 46.7479 141.541 36.7857 162.322 30.0357C182.378 23.517 203.773 20 226 20"
                        stroke="url(#paint0_linear_1778_16708)" stroke-width="40" stroke-miterlimit="10"
                        stroke-linecap="round" style="stroke-dashoffset: 649px; stroke-width: 40;"></path>
                    <defs>
                        <linearGradient id="paint0_linear_1778_16708" x1="225.997" y1="20" x2="225.997" y2="432"
                            gradientUnits="userSpaceOnUse" class="">
                            <stop stop-color="#ff0000" class=""></stop>
                            <stop offset="0.964085" stop-color="#ff0000" class=""></stop>
                        </linearGradient>
                    </defs>
                </svg>
            </div>
        </div>
        <!-- 动态标题 -->
        <div class="mx-auto text-[#000] relative z-3 pct:text-72px pct:leading-[86px] mot:text-44px mot:leading-[52px] pc:w-1312rpx pc:py-239rpx pc:text-center mo:w-328rpx mo:text-center mo:py-100rpx pad:w-720rpx pad:text-center pad:py-128rpx">
            <div ksp-slogan="" class="" style="transform: scale(0.2);opacity: 0;">gsap<br>ScrollTrigger</div>
        </div>
        <div class="bg-img ksp-cover"></div>
    </div>
    <div style="height: 100vh; width: 100%;background-color: rgb(148, 158, 101);"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
    <script>

        const paths = document.querySelectorAll('.svg-path');
        const bgImg = document.querySelector('.bg-img[svg-group]');

        // 创建GSAP时间线
        const tl = gsap.timeline({
            scrollTrigger: {
                trigger: paths[0], // 以第一个路径作为触发器
                start: "top 80%",   // 当元素距离视口顶部80%时开始动画
                toggleActions: "restart reverse reverse reverse" // 控制动画的播放与回退
            }
        });
        
       // 获取第一个路径的长度并设置初始的描边样式
        const firstPathLength = paths[0].getTotalLength();
        paths[0].style.strokeDasharray = firstPathLength;
        paths[0].style.strokeDashoffset = firstPathLength;
        
        // 执行路径动画
        tl.to(paths[0], {
            strokeDashoffset: 0,
            duration: 1,
            ease: "linear"
        });
        // 设置初始缩放比例
        tl.to('[ksp-slogan]',{
            scale: 1,
            opacity: 1,
            duration: 1,
            ease: "linear",
        },'<')//“<”表示第一个路径和标题同步执行
        // 然后画第二个路径
        const secondPathLength = paths[1].getTotalLength();
        paths[1].style.strokeDasharray = secondPathLength;
        paths[1].style.strokeDashoffset = secondPathLength;

        tl.to(paths[1], {
            strokeDashoffset: 0,
            duration: 1,
            ease: "linear",
        }); 
        
        // 放大 .bg-img 并同时减少 stroke-width
        tl.to(bgImg, {
            scale: 5.2,
            duration: 1,
            ease: "linear"
        })
        .to(paths, {
            strokeWidth: 8, // 将 stroke-width 降到 8
            duration: 0.5,
            ease: "linear"
        }, "-=1");  // 两个动画同时进行,时间对齐

        // 手动处理反向动画
        tl.eventCallback("onReverseComplete", () => {
            paths.forEach(path => {
                path.style.strokeDashoffset = path.getTotalLength(); // 恢复初始状态
            });
        });
    </script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值