React实现过渡效果更新时间展示

 

创建一个组件,实时展示时分秒,并且动态更新数据。

数据变化时利用过渡效果动态更新。

利用两个元素,重叠在一个位置,以达到交替变化的效果

//创建秒显示节点
<div className="text second">
	<CSSTransition
		in="{renderSecond}"
		timeout="{1000}"
		classNames="fade"
		unmountOnExit="{!renderSecond}"
	>
		{() =>
		<div className="fade">{secondeA}</div>
		}
	</CSSTransition>
	<CSSTransition
		in="{!renderSecond}"
		timeout="{1000}"
		classNames="fade"
		unmountOnExit="{renderSecond}"
	>
		{() =>
		<div className="fade">{secondeB}</div>
		}
	</CSSTransition>
</div>

 

利用官方提供的过渡动画库react-transition-group

文档地址https://reactcommunity.org/react-transition-group/https://reactcommunity.org/react-transition-group/

使用了CSSTransition组件构建过渡动画

  • in<boolean>:用来触发元素enter或exit
  • timeout<number>:实现过渡的时间,ms
  •  classNames<string>:注意是Names,不是Name。组件会依据提供的类名,进行过渡类名的拼接。(classNames='fade'->className='fade fade-enter fade-enter-active')
  • unmountOnExit<boolean>:动画结束后是否删除节点
<CSSTransition
    in={renderMinute}
    timeout={1000}
    classNames="fade"
    unmountOnExit={!renderMinute}
>
    {() => <div className="fade">{minuteA}</div>}
</CSSTransition>
//将两个元素重叠在一个位置
//对类fade-enter,fade-enter-active,fade-exit,fade-exit-active进行动画编写
.text {
	position: relative;
	width: 25px;
	display: flex;
	justify-content: center;
	align-items: center;
	.fade {
		position: absolute;
		&-enter {
			transform: translateY(-20px);
			opacity: 0;
			&-active {
				transform: translateY(0);
				opacity: 1;
				transition: all 0.8s ease-out;
			}
		}
		&-exit {
			transform: translateY(0);
			opacity: 0.5;
			&-active {
				transform: translateY(20px);
				opacity: 0;
				transition: all 0.6s ease-in;
			}
		}
	}
}

 在组件挂载结束后开启定时器,对时间进行更新

//定义两个响应式变量作为秒元素的两个节点
//定义记录当前渲染标记,用来记录显示哪一个元素
//挂载后开启定时器,每一秒都会进行数据更新,根据渲染标记,更新不同的响应式变量,起到新时间替换旧时间的动画效果
const AnimatedText = () => {
	const [secondeA, setSecondeA] = useState<string>(dayjs().format('ss'))
	const [secondeB, setSecondeB] = useState<string>(dayjs().format('ss'))
	const [renderSecond, setRenderSecond] = useState<boolean>(true)
	const renderSecondRef = useRef<boolean>(true)

	useEffect(() => {
		const interval = setInterval(() => {
			if (!renderSecondRef.current) {
				setSecondeA(dayjs().format('ss'))
			} else {
				setSecondeB(dayjs().format('ss'))
			}
			setRenderSecond(a => {
				renderSecondRef.current = !a
				return !a
			})
		}, 1000)
		return () => clearInterval(interval)
	}, [])
}

 

import { useState, useEffect, useRef } from 'react'
import { CSSTransition } from 'react-transition-group'
import './test.less'
import dayjs from 'dayjs'

const AnimatedText = () => {
	const [secondeA, setSecondeA] = useState<string>(dayjs().format('ss'))
	const [secondeB, setSecondeB] = useState<string>(dayjs().format('ss'))
	const [renderSecond, setRenderSecond] = useState<boolean>(true)
	const renderSecondRef = useRef<boolean>(true)

	const [minuteA, setMinuteA] = useState<string>(dayjs().format('mm'))
	const [minuteB, setMinuteB] = useState<string>(dayjs().format('mm'))
	const [renderMinute, setRenderMinute] = useState<boolean>(true)
	const renderMinuteRef = useRef<boolean>(true)

	const [hourA, setHourA] = useState<string>(dayjs().format('HH'))
	const [hourB, setHourB] = useState<string>(dayjs().format('HH'))
	const [renderHour, setRenderHour] = useState<boolean>(true)
	const renderHourRef = useRef<boolean>(true)

	useEffect(() => {
		const interval = setInterval(() => {
			if (!renderSecondRef.current) {
				setSecondeA(dayjs().format('ss'))
			} else {
				setSecondeB(dayjs().format('ss'))
			}
			setRenderSecond(a => {
				renderSecondRef.current = !a
				return !a
			})
		}, 1000)
		return () => clearInterval(interval)
	}, [])

	useEffect(() => {
		const interval = setInterval(() => {
			if (dayjs().format('ss') !== '00') return
			if (!renderMinuteRef.current) {
				setMinuteA(dayjs().format('mm'))
			} else {
				setMinuteB(dayjs().format('mm'))
			}
			setRenderMinute(a => {
				renderMinuteRef.current = !a
				return !a
			})
		}, 1000)
		return () => clearInterval(interval)
	}, [])

	useEffect(() => {
		const interval = setInterval(() => {
			if (dayjs().format('mm') !== '00') return
			if (!renderHourRef.current) {
				setHourA(dayjs().format('HH'))
			} else {
				setHourB(dayjs().format('HH'))
			}
			setRenderHour(a => {
				renderHourRef.current = !a
				return !a
			})
		}, 1000)
		return () => clearInterval(interval)
	}, [])

	return (
		<>
			<div className="area">
				<div className="text hour">
					<CSSTransition
						in={renderHour}
						timeout={1000}
						classNames="fade"
						unmountOnExit={!renderHour}
					>
						{() => <div className="fade">{hourA}</div>}
					</CSSTransition>
					<CSSTransition
						in={!renderHour}
						timeout={1000}
						classNames="fade"
						unmountOnExit={renderHour}
					>
						{() => <div className="fade">{hourB}</div>}
					</CSSTransition>
				</div>
				<div className="text">:</div>
				<div className="text minute">
					<CSSTransition
						in={renderMinute}
						timeout={1000}
						classNames="fade"
						unmountOnExit={!renderMinute}
					>
						{() => <div className="fade">{minuteA}</div>}
					</CSSTransition>
					<CSSTransition
						in={!renderMinute}
						timeout={1000}
						classNames="fade"
						unmountOnExit={renderMinute}
					>
						{() => <div className="fade">{minuteB}</div>}
					</CSSTransition>
				</div>
				<div className="text">:</div>
				<div className="text second">
					<CSSTransition
						in={renderSecond}
						timeout={1000}
						classNames="fade"
						unmountOnExit={!renderSecond}
					>
						{() => <div className="fade">{secondeA}</div>}
					</CSSTransition>
					<CSSTransition
						in={!renderSecond}
						timeout={1000}
						classNames="fade"
						unmountOnExit={renderSecond}
					>
						{() => <div className="fade">{secondeB}</div>}
					</CSSTransition>
				</div>
			</div>
		</>
	)
}

export default AnimatedText
.area {
	display: flex;
	justify-content: center;
	align-items: center;
	width: 100%;
	.text {
		position: relative;
		width: 25px;
		display: flex;
		justify-content: center;
		align-items: center;
		.fade {
			position: absolute;
			&-enter {
				transform: translateY(-20px);
				opacity: 0;
				&-active {
					transform: translateY(0);
					opacity: 1;
					transition: all 0.8s ease-out;
				}
			}
			&-exit {
				transform: translateY(0);
				opacity: 0.5;
				&-active {
					transform: translateY(20px);
					opacity: 0;
					transition: all 0.6s ease-in;
				}
			}
		}
	}
}

 

posted @ 2024-07-29 09:12  Karle  阅读(9)  评论(0编辑  收藏  举报