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 大佬