Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
374 views
in Technique[技术] by (71.8m points)

javascript - Triggering an animation from keyframes on scroll in React

I'm trying to implement an animation set up by keyframes when a div enters the screen. So basically whilst the user scrolss, I have several animations that so far work but they are based on singles transforms (opacity, translation in axis).

What I have so far

import React, {useState, useRef, useLayoutEffect} from 'react'
import AboutMeIcon from "./AboutMeIcons"
import iconsArray from "../iconsArray"
import styled, {keyframes} from "styled-components";

    const bouncing = keyframes`
        0%   { transform: scale(1,1)      translateY(0); }
        10%  { transform: scale(1.1,.9)   translateY(0); }
        30%  { transform: scale(.9,1.1)   translateY(-100px); }
        50%  { transform: scale(1.05,.95) translateY(0); }
        57%  { transform: scale(1,1)      translateY(-7px); }
        64%  { transform: scale(1,1)      translateY(0); }
        100% { transform: scale(1,1)      translateY(0); }
    `

const DivTitleWrapper = styled.div `
        transform: translateX(${({animate}) => (animate ? "0" : "-100vw")});
        transition: transform 1s;
        width: 100vw;
        display: flex;
        justify-content: center;
        height: 120px;
        border-radius: 0 0 100px 100px;
        margin-bottom: 30px;
    `;

 const ImageWrapper = styled.div `
        height: 400px;
        position: relative;
        animation: ${({animation}) => (animation ? bouncing : null)} cubic-bezier(0.280, 0.840, 0.420, 1);
        &::before {
            content: "";
            width: 100%;
            height: 0;
            transition: 0.4s ease;
            background-color: #283647;
            opacity: 0.5;
            position: absolute;
            top: 0;
            left: 0;
        }

        h2{
            left: 50%;
            top: 50%;
            transform: translate(-50%,-50%);
            position: absolute;
            margin:0;
            opacity:0;
            transition-delay:0.3s;
            transition: 1s ease;
            font-family: 'Raleway', sans-serif;
            color: #f5f5f5;
            z-index: 20;
            width: 100%;
            text-align: center;
        }

        &:hover {
            h2 {
                opacity: 1;
            }
        }

        &::after {
            content: "";
            width: 100%;
            height: 0;
            opacity: 0.5;
            transition: 0.4s ease;
            background-color: #283647;
            position: absolute;
            bottom: 0;
            left: 0;
        }

        &:hover::before{
            height: 50%;
        }

        &:hover::after{
            height: 50%;
        }
    `

On use LayoutEffect hook I set the state for each of the elements I want to animate (for the purpose of this question I will only add two)

const [show, doShow] = useState({
        itemOne: false,
        itemSix: false
    }) 

const ref = useRef(null),
        refTwo = useRef(null),
        refThree = useRef(null),
        refFour = useRef(null),
        refFive = useRef(null),
        refSix = useRef(null)

    useLayoutEffect(() => {
        const topPos = element => element.getBoundingClientRect().top

        const divPos1 = topPos(ref.current),
              imagesDiv = topPos(refSix.current)

        const scrollHandler = () => {
            const scrolPos = window.scrollY + window.innerHeight
            if(divPos1 < scrolPos) {
                doShow(state => ({...state, itemOne: true}))
            }
            if(imagesDiv < scrolPos) {
                doShow(state => ({...state, itemSix:true}))
            }

        }
        window.addEventListener("scroll", scrollHandler)

        return () => {
            window.removeEventListener("scroll", scrollHandler)
        };
    }, [])

What my functional component returns (removed most of it to avoid cluttering of information)

 return(
        <section className="aboutMeSection">
            <DivTitleWrapper animate={show.itemOne} ref={ref}>
                <H1 className="aboutMeTitle" opacity={show.itemTwo} ref={refTwo}>About Me</H1>
            </DivTitleWrapper>
            <div className="me">
                {imageArray.map((image, index) => {
                    return (
                            <ImageWrapper ref={refSix} animation={show.itemSix}  className={"imageWrapper" + index}>
                                ///some images being layed out
                            </ImageWrapper>
                        )
                    })}
                </div>
        </section>
    )

My problem at the moment is that when the user scrolls to the point where the state is updated for the div with refSix, the animation is not being triggering but for the div with refOne I have no issues.

Am I missing something here?

Many thanks and happy new year

EDIT: Added styled div that is currently working


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...