首页 > 解决方案 > setInterval() 的奇怪行为

问题描述

我正在尝试用 js 为一些简单的图表制作动画。我想让它们一个接一个地升起,从它们可见的时候开始。当图表持有者是第一个元素时,一切都很好,但是当我在它上面添加一些空间来测试滚动时,它就像 setInterval() 一样立即开始,而我设置了延迟

我尝试了各种谷歌修复,一些循环,并设置了 setinterval 的超时

const chartIsInView = el => {
    const scroll = window.scrollY || window.pageYOffset
    const boundsTop = el.getBoundingClientRect().top + scroll

    const viewport = {
        top: scroll,
        bottom: scroll + window.innerHeight,
    }

    const bounds = {
        top: boundsTop,
        bottom: boundsTop + el.clientHeight,
    }

    return ( bounds.bottom >= viewport.top && bounds.bottom <= viewport.bottom ) 
        || ( bounds.top <= viewport.bottom && bounds.top >= viewport.top );
}

var i = 0

function animate(e){
    e[i].classList.remove("animate")
    i++
}

document.addEventListener( 'DOMContentLoaded', () => {
    const tester = document.querySelector( '.container--chart' )
    const answer = document.querySelectorAll( '.percentage' )

    var IntervId = setInterval(
        handler = () => raf(() => {
            if (i>=11) {
                clearInterval(IntervId)
            }
            if (chartIsInView( tester )){
                animate(answer)
            }
        }
    ),500)

    handler()

    window.addEventListener( 'scroll', handler )
});

const raf = 
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function( callback ) {
        window.setTimeout( callback, 1000 / 60 )
    }
.spacer{
    height: 1000px;
}
.container--chart
{
    display: flex;
    justify-content: space-between;
    height: 150px;
    width: 340px;
    align-items: flex-end;
}
.percentage
{
    height: 150px;
    width: 23px;
    border-radius: 2px;
    background: rgba(114,56,235,1);
    background: -moz-linear-gradient(top, rgba(114,56,235,1) 0%, rgba(219,208,246,1) 100%);
    background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(114,56,235,1)), color-stop(100%, rgba(219,208,246,1)));
    background: -webkit-linear-gradient(top, rgba(114,56,235,1) 0%, rgba(219,208,246,1) 100%);
    background: -o-linear-gradient(top, rgba(114,56,235,1) 0%, rgba(219,208,246,1) 100%);
    background: -ms-linear-gradient(top, rgba(114,56,235,1) 0%, rgba(219,208,246,1) 100%);
    background: linear-gradient(to bottom, rgba(114,56,235,1) 0%, rgba(219,208,246,1) 100%);
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7238eb', endColorstr='#dbd0f6', GradientType=0 );
}
.percentage--one
{
    max-height: 100%;

}
.percentage--two
{
    max-height: 133px;
    background:#E0D5F9;
}
.percentage--three
{
    max-height: 111px;

}
.percentage--four
{
    max-height: 87px;

}
.percentage--five
{
    max-height: 65px;
}
.percentage--six
{
    max-height: 55px;
}
.percentage--seven
{
    max-height: 45px;
}
.percentage--eight
{
    max-height: 35px;
}
.percentage--nine
{
    max-height: 25px;
}
.percentage--ten
{
    max-height: 20px;
}
.percentage--eleven
{
    max-height: 15px;
}
.percentage--twelve
{
    max-height: 10px;
}

.percentage
{
    -webkit-transition: max-height 1s; 
    -moz-transition: max-height 1s; 
    -ms-transition: max-height 1s; 
    -o-transition: max-height 1s; 
    transition: max-height 1s;  
    overflow: hidden;
    /* do animacji */
    /* max-height: 0; */
}
.percentage:hover{
    height: 500px;
}
.faded-colour{
    background: #EFEBFB;
}
.animate{
    max-height: 0;
}
<!-- <div class="spacer"></div> -->
<div class="holder">
    <div class="container--chart">
        <div class="percentage percentage--one animate"></div>
        <div class="percentage percentage--two animate"></div>
        <div class="percentage percentage--three faded-colour animate"></div>
        <div class="percentage percentage--four faded-colour animate"></div>
        <div class="percentage percentage--five faded-colour animate"></div>
        <div class="percentage percentage--six faded-colour animate"></div>
        <div class="percentage percentage--seven faded-colour animate"></div>
        <div class="percentage percentage--eight faded-colour animate"></div>
        <div class="percentage percentage--nine faded-colour animate"></div>
        <div class="percentage percentage--ten faded-colour animate"></div>
        <div class="percentage percentage--eleven faded-colour animate"></div>
        <div class="percentage percentage--twelve faded-colour animate"></div>
    </div>
</div>
<div class="spacer"></div>

标签: javascripthtmlcsschartssetinterval

解决方案


密码笔

const chartIsInView = el => {
    const scroll = window.scrollY || window.pageYOffset
    const boundsTop = el.getBoundingClientRect().top + scroll

    const viewport = {
        top: scroll,
        bottom: scroll + window.innerHeight,
    }

    const bounds = {
        top: boundsTop,
        bottom: boundsTop + el.clientHeight,
    }

    return ( bounds.bottom >= viewport.top && bounds.bottom <= viewport.bottom ) 
        || ( bounds.top <= viewport.bottom && bounds.top >= viewport.top );
}

var i = 0

function animate(e){
    e[i].classList.remove("animate")
    i++
}

document.addEventListener( 'DOMContentLoaded', () => {
  let handlerTriggered = false;
    const tester = document.querySelector( '.container--chart' )
    const answer = document.querySelectorAll( '.percentage' )

    var IntervId = setInterval(
        handler = () => raf(() => {
            if (i>=11) {
                clearInterval(IntervId)
            }
            if (chartIsInView( tester )){
                animate(answer)
            }
        }
    )
    ,500)

    handler()

    window.addEventListener( 'scroll', () => {
      if (!handlerTriggered) {
        handlerTriggered = true;
        handler();
      }
    } )
});

const raf = 
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function( callback ) {
        window.setTimeout( callback, 1000 / 60 )
    }

handler() 附加到滚动事件并在滚动期间被触发很多次。添加布尔标志以检查它是否已经启动。


推荐阅读