50天50个小项目 (React19 + Tailwindcss V4) ✨ Form Wave(表单label波动效果)
中children数组中添加子路由path: '/',...})),},],},constants/index.tsx 添加组件预览常量省略部分....省略部分....id: 8,},
·
📅 我们继续 50 个小项目挑战!—— FormWave 组件
仓库地址:https://gitee.com/hhm-hhm/50days50projects.git

🌀 组件目标
- 构建一个美观、动态的登录表单,重点在于实现带有浮动标签(
floating label)的输入框体验,提升交互感知和视觉效果,适合作为任何登录注册模块的基础模板。
🔧 FormWave.tsx 组件实现
import React, { useState } from 'react'
const FormWave: React.FC = () => {
const [emailValue, setEmailValue] = useState<string>('')
const [passwordValue, setPasswordValue] = useState<string>('')
const [activeInput, setActiveInput] = useState<'email' | 'password' | null>(null)
const handleBlur = (inputName: 'email' | 'password') => {
if (
(inputName === 'email' && !emailValue) ||
(inputName === 'password' && !passwordValue)
) {
setActiveInput(null)
}
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
// 可在此添加登录逻辑
console.log({ email: emailValue, password: passwordValue })
}
return (
<div className="flex h-screen items-center justify-center bg-gray-800 text-gray-300">
<div className="rounded-2xl bg-gray-500/60 p-12 text-center">
<h1 className="text-4xl font-bold text-gray-300">Please Login</h1>
<form onSubmit={handleSubmit} className="mt-6">
{/* Email Input */}
<div className="form-control relative mt-10 border-b-2 border-b-white">
<input
className="peer relative z-10 w-full bg-transparent py-3 text-white focus:border-sky-300 focus:outline-none"
type="text"
required
value={emailValue}
onChange={(e) => setEmailValue(e.target.value)}
onFocus={() => setActiveInput('email')}
onBlur={() => handleBlur('email')}
/>
<label className="pointer-events-none absolute top-4 left-0">
{'Email'.split('').map((letter, idx) => (
<span
key={idx}
className={`inline-block min-w-[5px] transform-gpu text-lg transition-all duration-300 ${
activeInput === 'email' || emailValue
? '-translate-y-8 text-sky-300'
: ''
}`}
style={{
transitionDelay: `${idx * 50}ms`,
transitionTimingFunction:
'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
}}>
{letter}
</span>
))}
</label>
</div>
{/* Password Input */}
<div className="form-control relative mt-10 border-b-2 border-b-white">
<input
className="peer relative z-10 w-full bg-transparent py-3 text-white focus:border-sky-300 focus:outline-none"
type="password"
required
value={passwordValue}
onChange={(e) => setPasswordValue(e.target.value)}
onFocus={() => setActiveInput('password')}
onBlur={() => handleBlur('password')}
/>
<label className="pointer-events-none absolute top-4 left-0">
{'Password'.split('').map((letter, idx) => (
<span
key={idx}
className={`inline-block min-w-[5px] transform-gpu text-lg transition-all duration-300 ${
activeInput === 'password' || passwordValue
? '-translate-y-8 text-sky-300'
: ''
}`}
style={{
transitionDelay: `${idx * 50}ms`,
transitionTimingFunction:
'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
}}>
{letter}
</span>
))}
</label>
</div>
<button
type="submit"
className="mt-10 w-full rounded bg-blue-500 px-4 py-2 font-bold hover:bg-blue-600 focus:ring-2 focus:ring-blue-400 focus:outline-none">
Login
</button>
<p className="mt-10">
Don't have an account?{' '}
<a href="#" className="text-blue-400 hover:underline">
Register
</a>
</p>
</form>
</div>
<div className="absolute right-20 bottom-10 text-2xl text-red-500">
CSDN@Hao_Harrision
</div>
</div>
)
}
export default FormWave
📝 关键实现说明(与 Vue 对应):
| 功能 | Vue 实现 | React + TS 实现 |
|---|---|---|
| 响应式数据 | ref() |
useState() |
| 双向绑定 | v-model |
value + onChange |
| 聚焦/失焦事件 | @focus, @blur |
onFocus, onBlur |
| 条件类名 | :class="{ ... }" |
模板字符串 + 三元/逻辑表达式 |
| 动态列表渲染 | v-for |
.map() |
| 表单提交 | <form> 默认行为 |
onSubmit + e.preventDefault() |
⚠️注意事项:
- Tailwind 支持
transform-gpu和-translate-y-8:确保你的 Tailwind 配置未禁用这些类(默认启用)。 - 过渡动画依赖
transition-all duration-300:配合transitionDelay和自定义贝塞尔曲线,实现“波浪式”上浮动效。 - 输入框 label 动画逻辑:
- 当输入框获得焦点 或 已有值时,label 上移并变色;
- 失焦且为空时,label 回落原位。
- 类型安全:
activeInput使用联合类型'email' | 'password' | null;- 所有事件处理器参数均有明确类型。
🎯 动画说明
| 类名 | 作用 |
|---|---|
peer / relative z-10 |
确保 input 在 label 之上,供 label 状态判断使用 |
-translate-y-8 |
控制文字上浮距离 |
transition-delay |
实现文字一个个浮动的动画延迟 |
transform-gpu |
使用 GPU 加速动画,提高性能和流畅度 |
focus:outline-none / focus:ring-2 |
聚焦时视觉反馈 |
min-w-[5px] |
保证字符宽度一致,不会断行 |
👉 实现点
- 标签浮动是通过
translate-y配合activeInput或绑定值来实现的。 - 使用
transition-delay实现了字符级别的延迟动画,让文字一个个浮动。 - 利用
cubic-bezier定义自定义缓动函数,提升动画的弹性和自然感。
🦌 路由组件 + 常量定义
router/index.tsx 中 children数组中添加子路由
{
path: '/',
element: <App />,
children: [
...
{
path: '/FormWave',
lazy: () =>import('@/projects/FormWave.tsx').then((mod) => ({
Component: mod.default,
})),
},
],
},
constants/index.tsx 添加组件预览常量
import demo8Img from '@/assets/pic-demo/demo-8.png'
省略部分....
export const projectList: ProjectItem[] = [
省略部分....
{
id: 8,
title: 'Form Wave',
image: demo8Img,
link: 'FormWave',
},
]
🚀 小结
这个组件通过 React的useState状态管理和 TailwindCSS 的实用工具类,完成了通用场景下的表单样式界面,可以为你以后的表单设计以及登录页面提供一些灵感进行参考!!!🚀
📅 明日预告: Sound Board!可实现点击发出对应的声音!🚀
原文链接:https://blog.csdn.net/qq_44808710/article/details/148387695
每天造一个轮子,码力暴涨不是梦!🚀
更多推荐



所有评论(0)