如何在css动画之后获取元素的位置(vanilla js)

时间:2018-06-04 15:47:03

标签: javascript css-animations

我正在开发一个涉及多个动画的项目,虽然其中大多数都可以通过css关键帧动画轻松完成,但其他人需要使用javascript,而且我对于如何执行这些动作有点野蛮。我将尽我所能来描述我不能在小提琴中展示的内容(我正在编写视频中的演示代码)。

页面中有几个部分,每个部分都有各种元素淡入淡出,旋转等。当每个部分滚动到视图中时,会向其添加“animate”类以触发css动画,其中一个这是一个svg元素,从视口的北部下降到它停放的视口的底部。但是,当用户继续向下滚动时,我需要在视口以南的视图外设置此svg元素,然后在下一部分滚动到视图中时重新输入。所以我试图在它停放时获取findSection函数中元素的位置(vanilla js please),即在其关键帧动画完成之后但是我到目前为止尝试的方法是获得前动画位置。如何在通过css动画后获取绝对定位元素的当前位置?如果总体上比我到目前为止做的更好,那么我会全力以赴,特别是如果我可以使用单个svg元素而不是在每个部分重复它。

非常感谢任何帮助/建议。

Whiskey T。

标记(每个部分):

<div class="section" id="section-1">
    <svg version="1.1" class="thing-svg" [ etc. ] >
        <g class="thing-path-group">
            <path class="thing-path" d=" ... " />
        </g>
    </svg>
    <!-- content -->
</div><!-- #section-1 -->

的CSS:

.thing-svg {
    position: absolute;
    width: 60px;
    height: 60px;
    left: calc(50% - 30px);
    top: -60px;
    opacity: 0;
    z-index: 9;
}

.animate .thing-svg {
    animation: dropIt 1.8s ease-in-out forwards .3s;
}

@keyframes dropIt {
    0% {
        top: -60px;
        opacity: 0;
    }
    3% {
        opacity: 1;
    }
    100% {
        top: calc(100vh - 60px);
        opacity: 1;
    }
}

的javascript:

const sections = document.querySelectorAll('.section');
const svgEl = document.querySelector('#svg-el');


window.addEventListener('scroll', debounce(findSection)); // yes, there's a debounce fn

function findSection(e) {

    let svgElPosition = svgEl.getBoundingClientRect();

    sections.forEach(section => {

        const sectionInAt = (window.scrollY + window.innerHeight) - section.offsetHeight / 2;

        // these both get the pre-css keyframe animation value of 'top', but I need the post-keyframe animation 'top' value
        console.log("svgElPosition.top", svgElPosition.top);
        console.log(window.getComputedStyle(svgEl, null).getPropertyValue("top"));


        // bottom of the section:
        const sectionBottom = section.offsetTop + section.offsetHeight;

        // isHalfShown is true while sectionInAt/triggerCoord > section.offsetTop (i.e., section is half viz)
        const isHalfShown = sectionInAt > section.offsetTop;

        // isNotScrolledPast is true while window.scrollY < imageBottom (i.e., image is still viz)
        const isNotScrolledPast = window.scrollY < sectionBottom;

        if (isHalfShown && isNotScrolledPast) {
            section.classList.add('animate');
        } else {
            section.classList.remove('animate');
        }

    });
}

2 个答案:

答案 0 :(得分:2)

您应该在元素上注册animationend事件监听器:

svgEl.addEventListener('animationend', function (event) {
    const svgRect = this.getBoundingClientRect();
});

每当CSS动画完成元素时就会触发,这是确定它已经完成的必然方法。另请注意,您可以使用animationstartanimationiterationanimationcancel事件。

答案 1 :(得分:0)

在这种情况下,我相信你最好的选择是使用setTimeout()等待动画完成的适当时间,然后在闭包函数中获取位置。这是一个示例代码段:

if (isHalfShown && isNotScrolledPast) {
    section.classList.add('animate');
    let timer = setTimeout(function() {
    let rect = element.getBoundingClientRect();
    console.log(rect.top, rect.right, rect.bottom, rect.left);
    },300); //.3 seconds, if I read that correctly from the CSS (maybe an extra .01 seconds or something as well for good measure)
}

此示例中未显式使用“timer”变量,但如果您需要取消动画以取消计时器,则它可能很有用(尽管您需要将此范围置于此条件语句之外)