三步搭建跨设备无线音频系统:Scream让你的声音自由穿梭
2026/5/16 21:36:23
📅 我们继续 50 个小项目挑战!——
FAQCollapse组件
仓库地址:https://gitee.com/hhm-hhm/50days50projects.git
构建一个带有动画效果的常见问题(FAQ)折叠面板组件。该组件支持点击展开/收起,并为每个问答项添加了优雅的过渡动画。
FAQCollapse.tsx 组件实现import React, { useState } from 'react' interface FAQItem { id: number question: string answer: string isOpen: boolean } const FAQCollapse: React.FC = () => { const [faqList, setFaqList] = useState<FAQItem[]>([ { id: 1, question: 'What is React?', answer: 'React is a JavaScript library for building user interfaces, developed by Facebook. It uses a component-based architecture and a virtual DOM for efficient rendering.', isOpen: false, }, { id: 2, question: 'How do I install Tailwind CSS in a Vite + React project?', answer: 'You can install Tailwind CSS by running: `npm install -D tailwindcss postcss autoprefixer`, then `npx tailwindcss init -p`, and configure `tailwind.config.js` and `postcss.config.js` accordingly.', isOpen: false, }, { id: 3, question: 'Why use TypeScript with React?', answer: 'TypeScript adds static typing to JavaScript, helping catch bugs at compile time, improving code maintainability, and providing better autocompletion and refactoring support in IDEs.', isOpen: false, }, { id: 4, question: 'Can I use this FAQ component in a production app?', answer: 'Yes! This component is built with best practices: type safety, proper state management, accessibility considerations, and responsive design using Tailwind CSS.', isOpen: false, }, ]) const toggleOpen = (id: number) => { setFaqList((prev) => prev.map((item) => (item.id === id ? { ...item, isOpen: !item.isOpen } : item)) ) } return ( <div className="m-12 flex flex-col items-center justify-center gap-8 text-white"> <h3 className="font-mono text-2xl font-bold">Frequently Asked Questions</h3> {faqList.map((item) => ( <div key={item.id} className="w-full max-w-2xl overflow-hidden rounded-2xl bg-gray-500 p-8"> <div className="flex cursor-pointer items-start justify-between" onClick={() => toggleOpen(item.id)}> <div className="text-xl font-bold">{item.question}</div> <div className="text-2xl font-bold select-none"> {item.isOpen ? '-' : '+'} </div> </div> {item.isOpen && ( <div className="mt-4 text-xl font-bold transition-all duration-500 ease-in-out"> {item.answer} </div> )} </div> ))} <div className="absolute right-20 bottom-10 text-2xl text-red-500"> CSDN@Hao_Harrision </div> </div> ) } export default FAQCollapseuseState<FAQItem[]>存储 FAQ 列表。FAQItem包含isOpen: boolean字段(通过扩展对象实现)。setFaqList(prev => prev.map(...))。toggleOpen(id)只翻转对应项的isOpen状态。<Transition>在 React 中没有直接等价物。{item.isOpen && <div className="transition-all duration-500 ease-in-out ...">...</div>}enter-from/leave-to的精细控制,但视觉效果非常接近。framer-motion或react-transition-group,但本场景无需。max-w-2xl替代原w-2xl(Tailwind 中w-2xl不是标准类,应为max-w-2xl)。select-none防止用户误选+/-符号。text-white),背景为bg-gray-500。动画局限性:React 条件渲染在元素“消失”时会立即卸载,因此收起动画无法完全执行。
如果你希望收起也有动画,需使用height或opacity控制 +onTransitionEnd,或使用第三方库。
✅ 但对 FAQ 场景,展开有动画、收起瞬时隐藏是常见且可接受的设计。
无障碍(a11y)建议(可选增强):
role="button"和aria-expanded。<div role="button" aria-expanded={item.isOpen} tabIndex={0} onKeyDown={(e) => e.key === 'Enter' && toggleOpen(item.id)} >| 类名 | 作用 |
|---|---|
m-12 | 外边距为 3rem |
flex,flex-col | 弹性布局并设置为纵向排列 |
items-center,justify-center | 内容居中对齐 |
gap-8 | 子元素之间间距为 2rem |
text-white | 设置文字颜色为白色 |
font-mono | 使用等宽字体 |
rounded-2xl | 圆角大小为 1rem |
bg-gray-500 | 设置背景颜色为灰色 |
p-8 | 内边距为 2rem |
cursor-pointer | 鼠标悬停时变为手型 |
overflow-hidden | 隐藏超出容器的内容,用于动画流畅展示 |
text-xl,text-2xl | 不同层级的文字大小 |
font-bold | 加粗字体 |
mt-4 | 上边距为 1rem |
这些类名帮助我们快速构建出一个居中的响应式布局,并确保视觉上的一致性和美观性。
router/index.tsx中children数组中添加子路由
{ path: '/', element: <App />, children: [ ... { path: '/FAQ', lazy: () => import('@/projects/FAQCollapse.tsx').then((mod) => ({ Component: mod.default, })), }, ], },constants/index.tsx 添加组件预览常量
import demo12Img from '@/assets/pic-demo/demo-12.png' 省略部分.... export const projectList: ProjectItem[] = [ 省略部分.... { id: 12, title: 'FAQ Collapse', image: demo12Img, link: 'FAQ', }, ]涵盖响应式系统、事件监听机制以及TailwindCSS的实用样式类。它不仅是一个教学示例,也可以作为开发调试工具的一部分,用于快速查看键盘事件的数据。
RandomChoicePicker组件,一个现代化的标签输入组件🚀
原文链接:https://blog.csdn.net/qq_44808710/article/details/148590104
每天造一个轮子,码力暴涨不是梦!🚀