首页 > 解决方案 > JS ForLoop 不起作用 - 页面上有多个元素的 IntersectionObserver

问题描述

我有一个简单的设置,使用intersectionObserver 在元素相交时向元素添加一个类。

如果一次只有一个元素滚动到视图中,则效果很好。

let lazyLoadSvg = document.getElementsByClassName('geometry-animation')

console.log(lazyLoadSvg)

for(let i = 0; i < lazyLoadSvg.length; i++){

    const observer2 = new IntersectionObserver(entries => {
     
        // Loop over the entries
        entries.forEach(entry => {

            // If the element is visible
            if (entry.isIntersecting) {

                // Run the animation
                targetGeometry = entry.target.children[0].children[0].getElementsByTagName('g');
                setTimeout(function() {
                    for(let i = 0; i < targetGeometry.length; i++){

                        setTimeout(function() {
            
                            targetGeometry[i].classList.add('geometry-active');
            
                        }, 50 * i);
            
                    }
                }, 1000)
            }
        });
    });

    // Tell the observer which elements to track
    observer2.observe(lazyLoadSvg[i]);

}

但是如果一次有多个元素相交,这将不起作用......如果有多个元素具有相同的 Y 位置,则只有其中一个元素会运行动画。

关于为什么会发生这种情况的任何建议或想法?

这是完整的代码片段:

let lazyLoadSvg = document.getElementsByClassName('geometry-animation')

console.log(lazyLoadSvg)

for(let i = 0; i < lazyLoadSvg.length; i++){

    const observer2 = new IntersectionObserver(entries => {
     
        // Loop over the entries
        entries.forEach(entry => {

            // If the element is visible
            if (entry.isIntersecting) {

                // Run the animation
                targetGeometry = entry.target.children[0].children[0].getElementsByTagName('g');
                setTimeout(function() {
                    for(let i = 0; i < targetGeometry.length; i++){

                        setTimeout(function() {
            
                            targetGeometry[i].classList.add('geometry-active');
            
                        }, 50 * i);
            
                    }
                }, 1000)
            }
        });
    });

    // Tell the observer which elements to track
    observer2.observe(lazyLoadSvg[i]);

}
.geometry-animation svg g g {
    opacity: 0;
    transition: all ease-in-out 400ms;
}

.geometry-animation svg g g.geometry-active {
    opacity: 1;
}

/*
Everything below this is general page styling
*/


.main-grid {
    display: grid;
    grid-template-columns: 1fr 18fr 1fr;
}

.main-content {
    grid-column: 2 / 3;
    grid-row: 1 / 2;
    overflow: hidden;
}

.main-copy {
    margin: auto;
    width: 78.1%;
    transition: all ease-in-out 0.8s;
}

.grid-template {
    display: grid;
    height: 100%;
}
.gt-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}
.gt-item p.style-1 {
    margin-top: 5%;
}

.gt-item p.style-2 {
    font-size: 16px;
    line-height: 24px;
    padding-left: 28px;
    padding-right: 20px;
    padding-bottom: 20px;
}
.gt-item p.style-2.underline {
    color: #f22450;
    text-decoration: underline;
}

.gt-padding {
    padding: 10%;
}
.gt-padding > * {
    padding-bottom: 8%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="fill" style="height: 100vh;"></div>
    <div class="main-grid">
        <div class="main-content main-copy" style="overflow: visible;">
            <div class="grid-template" style="grid-template-columns: repeat(3, 1fr); gap: 5vw; height: 750px; margin-top: 150px; margin-bottom: 150px; color: white;">


                <!-- The div below is repeated three times -->


                <div style="height: 100%;background-color: #15141b; justify-content: flex-start;" class="gt-item box-shadow">
                    <div class="gt-padding gt-item" style="justify-content: flex-start; width: 80%;">
                        <div class="geometry-animation" style="width: 75%;">
                            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500; fill:#E4E030;" xml:space="preserve">
                                <g>
                                    <g class="svg-animated">
                                            <linearGradient id="SVGID_83_" gradientUnits="userSpaceOnUse" x1="50.5953" y1="366.6901" x2="454.8215" y2="133.3099" gradientTransform="matrix(-4.163336e-17 0.2146 -0.2146 -4.163336e-17 208.488 214.677)">
                                            <stop  offset="0.1058" style="stop-color:#E4E030"/>
                                            <stop  offset="0.2778" style="stop-color:#E8E7E7"/>
                                            <stop  offset="0.5847" style="stop-color:#E8E7E7"/>
                                            <stop  offset="0.6434" style="stop-color:#E8E7E7;stop-opacity:0.8728"/>
                                            <stop  offset="1" style="stop-color:#E8E7E7;stop-opacity:0.5"/>
                                        </linearGradient>
                                        <polygon class="st82" points="204.8,282.3 204.8,255.5 191.4,232.3 168.2,218.9 141.4,218.9 118.2,232.3 104.8,255.5 104.8,282.3 
                                            118.2,305.5 141.4,318.9 168.2,318.9 191.4,305.5"/>
                                    </g>
                                </g>
                            </svg>
                        </div>
                        <h1 style="width: 100%; font-size: 40px; font-weight: 800;">Yellow</h1>
                        <p style="border-top: solid 1px #333140; padding-top: 10%; color: grey;">A yellow circle should appear above this text when scrolled into view</p>
                    </div>
                </div>


                <!-- The div above is repeated three times -->


                <div style="height: 100%;background-color: #15141b; justify-content: flex-start;" class="gt-item box-shadow">
                    <div class="gt-padding gt-item" style="justify-content: flex-start; width: 80%;">
                        <div class="geometry-animation" style="width: 75%;">
                            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500; fill:#E4E030;" xml:space="preserve">
                                <g>
                                    <g class="svg-animated">
                                            <linearGradient id="SVGID_83_" gradientUnits="userSpaceOnUse" x1="50.5953" y1="366.6901" x2="454.8215" y2="133.3099" gradientTransform="matrix(-4.163336e-17 0.2146 -0.2146 -4.163336e-17 208.488 214.677)">
                                            <stop  offset="0.1058" style="stop-color:#E4E030"/>
                                            <stop  offset="0.2778" style="stop-color:#E8E7E7"/>
                                            <stop  offset="0.5847" style="stop-color:#E8E7E7"/>
                                            <stop  offset="0.6434" style="stop-color:#E8E7E7;stop-opacity:0.8728"/>
                                            <stop  offset="1" style="stop-color:#E8E7E7;stop-opacity:0.5"/>
                                        </linearGradient>
                                        <polygon class="st82" points="204.8,282.3 204.8,255.5 191.4,232.3 168.2,218.9 141.4,218.9 118.2,232.3 104.8,255.5 104.8,282.3 
                                            118.2,305.5 141.4,318.9 168.2,318.9 191.4,305.5"/>
                                    </g>
                                </g>
                            </svg>
                        </div>
                        <h1 style="width: 100%; font-size: 40px; font-weight: 800;">Yellow</h1>
                        <p style="border-top: solid 1px #333140; padding-top: 10%; color: grey;">A yellow circle should appear above this text when scrolled into view</p>
                    </div>
                </div>



                <div style="height: 100%;background-color: #15141b; justify-content: flex-start;" class="gt-item box-shadow">
                    <div class="gt-padding gt-item" style="justify-content: flex-start; width: 80%;">
                        <div class="geometry-animation" style="width: 75%;">
                            <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500; fill:#E4E030;" xml:space="preserve">
                                <g>
                                    <g class="svg-animated">
                                        
                                            <linearGradient id="SVGID_83_" gradientUnits="userSpaceOnUse" x1="50.5953" y1="366.6901" x2="454.8215" y2="133.3099" gradientTransform="matrix(-4.163336e-17 0.2146 -0.2146 -4.163336e-17 208.488 214.677)">
                                            <stop  offset="0.1058" style="stop-color:#E4E030"/>
                                            <stop  offset="0.2778" style="stop-color:#E8E7E7"/>
                                            <stop  offset="0.5847" style="stop-color:#E8E7E7"/>
                                            <stop  offset="0.6434" style="stop-color:#E8E7E7;stop-opacity:0.8728"/>
                                            <stop  offset="1" style="stop-color:#E8E7E7;stop-opacity:0.5"/>
                                        </linearGradient>
                                        <polygon class="st82" points="204.8,282.3 204.8,255.5 191.4,232.3 168.2,218.9 141.4,218.9 118.2,232.3 104.8,255.5 104.8,282.3 
                                            118.2,305.5 141.4,318.9 168.2,318.9 191.4,305.5"/>
                                    </g>
                                </g>
                            </svg>
                        </div>
                        <h1 style="width: 100%; font-size: 40px; font-weight: 800;">Yellow</h1>
                        <p style="border-top: solid 1px #333140; padding-top: 10%; color: grey;">A yellow circle should appear above this text when scrolled into view</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

标签: javascripthtmljquerycsslogic

解决方案


尝试更改IntersectionObserver阈值并将其设置为0.

此外,您不需要IntersectionObserver为每个lazyLoadSvg项目创建实例;所以将IntersectionObserver创作移出循环。

我制作了这个沙箱来模仿你的情况,它工作正常。

希望这对你有用。


推荐阅读