React实现块依次从下到上进入的动画

app.js

import React, { useEffect, useState } from 'react';

import Nav from './components/Nav';
import Footer from './components/Footer';
import About from './components/About';
import Product from './components/Product';
import Service from './components/Service';
import Value from './components/Value';
import JoinUs from './components/JoinUs';
import ContactUs from './components/ContactUs';

import './index.scss';
import { IntlProvider, addLocaleData } from 'react-intl';
import zh_CN from '@/locales/zh-CN';
import en_US from '@/locales/en-US';

const getLang = () => {
    const search = window.location.search;
    const params = new URLSearchParams(search);
    return params.get('lang') || 'en';
};

const App = () => {
    const [scrollTop, setScrollTop] = useState(0);
    const [locale, setLocale] = useState(getLang());
    const messages = {
        zh: zh_CN,
        en: en_US
    };
    const handleScroll = () => {
        const top =
            document.documentElement.scrollTop || document.body.scrollTop;
        setScrollTop(top);
    };

    useEffect(() => {
        handleScroll();
        window.addEventListener('scroll', handleScroll);
        return () => {
            window.removeEventListener('scroll', handleScroll);
        };
    }, []);

    return (
        <IntlProvider locale="en" messages={messages[locale]}>
            <div className={`page-content ${locale}`}>
                <Nav scrollTop={scrollTop} />
                <About locale={locale} />
                <Product scrollTop={scrollTop} />
                <Service scrollTop={scrollTop} />
                <Value scrollTop={scrollTop} />
                <JoinUs scrollTop={scrollTop} />
                <ContactUs locale={locale} scrollTop={scrollTop} />
                <Footer />
            </div>
        </IntlProvider>
    );
};
export default App;

在app.js中传递scrollTop给组件,用来计算动画触发时的高度

随便一个组件的代码:

import React, { useState, useEffect, useRef } from 'react';
import { Animate } from 'react-move';
import { FormattedMessage } from 'react-intl';
import { easeQuadInOut } from 'd3-ease';
import Location from '@/assets/svg/location.svg';
import ArrowUp from '@/assets/svg/arrow-down.svg';
import Globe from '@/assets/images/globe.png';
import './index.scss';

const JoinUs = ({ scrollTop }) => {
    const ref = useRef();
    const [options, setOptions] = useState(false);
    const showOption = () => {
        setOptions(!options);
    };

    const handleScroll = top => {
        const obj = ref.current;
        const clientHeight = document.documentElement.clientHeight;
        const diff = clientHeight - obj.offsetTop + top;

        const doms = document.querySelectorAll('.section-joinus__select');
        Array.from(doms).forEach((item, index) => {
            if (diff > 0 && !item.style.animation) {
                item.style.animation = `slideUpBox 1s ease-in ${0.2 *
                    index}s forwards`;
            }
        });

        const domText = document.querySelector('.section-joinus__resc');
        if (diff > 0 && !domText.style.animation) {
            domText.style.animation = `slideUp 1s ease-in forwards`;
        }
    };

    useEffect(() => {
        handleScroll(scrollTop);
    }, [scrollTop]);

    const [items, setItems] = useState([
        {
            id: 0,
            country: <FormattedMessage id="component.join.country1" />,
            work1: <FormattedMessage id="component.join.work1" />,
            work2: <FormattedMessage id="component.join.work2" />,
            btntxt: <FormattedMessage id="component.join.btntxt" />
        },
        {
            id: 1,
            country: <FormattedMessage id="component.join.country2" />,
            work1: <FormattedMessage id="component.join.work3" />,
            work2: <FormattedMessage id="component.join.work4" />,
            btntxt: <FormattedMessage id="component.join.btntxt" />
        }
    ]);

    return (
        <div className="section section-joinus" ref={ref}>
            <div className="padding37">
                <div className="page-wrapper-inner">
                    <h4>
                        <FormattedMessage id="component.join.inner" />
                    </h4>
                    <div className="section-joinus__resc">
                        <FormattedMessage id="component.join.resc" />
                    </div>
                    {items.map((item, index) => (
                        <div className="section-joinus__select" key={index}>
                            <div
                                className="country"
                                onClick={() => showOption()}
                            >
                                <i className="i-pos">
                                    <Location />
                                </i>
                                <span>{item.country}</span>
                                <i className="i-up">
                                    <ArrowUp />
                                </i>
                            </div>
                            <div
                                className="option"
                                style={{
                                    height:
                                        index === 0
                                            ? options
                                                ? '0'
                                                : '200px'
                                            : options
                                            ? '200px'
                                            : '0'
                                }}
                            >
                                <ul>
                                    <li>{item.work1}</li>
                                    <li>{item.work2}</li>
                                </ul>
                                <button>{item.btntxt}</button>
                            </div>
                        </div>
                    ))}
                </div>
            </div>

            <p className="section-joinus__china">
                <FormattedMessage id="component.join.china" />
            </p>
            <p className="section-joinus__singa">
                <FormattedMessage id="component.join.singa" />
            </p>
            <i className="section-joinus__circleChina"></i>
            <i className="section-joinus__circleSinga"></i>
            <div className="section-joinus__bg">
                <img src={Globe} />
            </div>
        </div>
    );
};
export default JoinUs;

  

ps:

forwards:当动画完成后,保持最后一个属性值(在最后一个关键帧中定义)。

------from  大佬

原文地址:https://www.cnblogs.com/nangras/p/11555620.html