创建欢迎页面
还原页面内容
将欢迎界面的代码修改成之前的样子,使用unocss的进行样式绘制,具体代码见链接。
添加第一个页面HTML
修改WeclomeLayout.tsx
组件,分上中下三部分,中间部分通过动画来滑动,其他部分不做处理,并根据linkMap
来映射下一页的跳转。
tsx
import { Link, useLocation, useOutlet, } from 'react-router-dom'
import { animated, useTransition } from 'react-spring'
import type { ReactNode } from 'react'
import { useRef } from 'react'
import logo from '../assets/images/logo.svg'
const linkMap: Record<string, string> = {
'/welcome/1': '/welcome/2',
'/welcome/2': '/welcome/3',
'/welcome/3': '/welcome/4',
'/welcome/4': '/welcome/xxx',
}
export const WelcomeLayout: React.FC = () => {
const map = useRef<Record<string, ReactNode>>({})
const location = useLocation() // 获取当前地址栏的信息
const outlet = useOutlet()
map.current[location.pathname] = outlet
const transitions = useTransition(location.pathname, {
from: { transform: location.pathname === '/welcome/1' ? 'translateX(0%)' : 'translateX(100%)' },
enter: { transform: 'translateX(0%)' },
leave: { transform: 'translateX(-100%)' },
config: { duration: 300 }
})
return (
<div>
<header>
<img src={logo} />
<h1>山竹记账</h1>
</header>
<main>
{transitions((style, pathname) =>
<animated.div key={pathname} style={style}>
{map.current[pathname]}
</animated.div>
)}
</main>
<footer>
<Link to={linkMap[location.pathname]}>下一页</Link>
<Link to="/welcome/xxx">跳过</Link>
</footer>
</div>
)
}
tsx
export const Welcome1: React.FC = () => {
return (
<div text-center>
<img src={p1} />
<h2 text-32px mt-48px>
会挣钱 <br/>
还要会省钱
</h2>
</div>
)
}
添加第一个页面的样式
底部下一页和跳过使用grid
布局进行分布区域,添加样式具体见链接。
完成 4 个界面
4个界面内容具体见链接。
优化动画的两个细节
- 提高流畅度
- 解决如果图片加载慢会闪烁的问题
中间部分页面开始动画操作的时候添加相对绝对定位,然后在离开后复位的时候在改为相对定位,提高动画的流畅程度,并将样式添加至<animated.div />
的style
内,详细代码见链接。
tsx
import { Link, useLocation, useOutlet, } from 'react-router-dom'
import { animated, useTransition } from 'react-spring'
import type { ReactNode } from 'react'
import { useRef, useState } from 'react'
import logo from '../assets/images/logo.svg'
const linkMap: Record<string, string> = {
'/welcome/1': '/welcome/2',
'/welcome/2': '/welcome/3',
'/welcome/3': '/welcome/4',
'/welcome/4': '/welcome/xxx',
}
export const WelcomeLayout: React.FC = () => {
const map = useRef<Record<string, ReactNode>>({})
const location = useLocation() // 获取当前地址栏的信息
const outlet = useOutlet()
map.current[location.pathname] = outlet
const [extraStyle, setExtraStyle] = useState({ position: 'relative' })
const transitions = useTransition(location.pathname, {
from: { transform: location.pathname === '/welcome/1' ? 'translateX(0%)' : 'translateX(100%)' },
enter: { transform: 'translateX(0%)' },
leave: { transform: 'translateX(-100%)' },
config: { duration: 300 },
onStart: () => {
setExtraStyle({ position: 'absolute' })
},
onRest: () => {
setExtraStyle({ position: 'relative' })
}
})
return (
<div className="bg-#5f34bf" h-screen flex flex-col items-stretch pb-16px>
<header shrink-0 text-center pt-64px>
<img src={logo} w-64px h-69px />
<h1 text="#D4D4EE" text-32px>山竹记账</h1>
</header>
<main shrink-1 grow-1 relative >
{transitions((style, pathname) =>
<animated.div key={pathname} style={{ ...style, ...extraStyle }} w="100%" h="100%" p-16px flex>
<div grow-1 bg-white flex justify-center items-center rounded-8px>
{map.current[pathname]}
</div>
</animated.div>
)}
</main>
<footer shrink-0 text-center text-24px text-white grid grid-cols-3 grid-rows-1>
<Link style={{ gridArea: '1 / 2 / 2 / 3' }} to={linkMap[location.pathname]}>下一页</Link>
<Link style={{ gridArea: '1 / 3 / 2 / 4' }} to="/welcome/xxx">跳过</Link>
</footer>
</div>
)
}