news 2025/12/29 9:45:44

50天50个小项目 (React19 + Tailwindcss V4) ✨| FAQ Collapse(问题解答折叠面板)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
50天50个小项目 (React19 + Tailwindcss V4) ✨| FAQ Collapse(问题解答折叠面板)

📅 我们继续 50 个小项目挑战!——FAQCollapse组件

仓库地址:https://gitee.com/hhm-hhm/50days50projects.git

构建一个带有动画效果的常见问题(FAQ)折叠面板组件。该组件支持点击展开/收起,并为每个问答项添加了优雅的过渡动画。

🌀 组件目标

  • 展示一组常见问题(FAQ)。
  • 每个问题可以独立展开与收起。
  • 使用 TailwindCSS 快速构建美观的 UI 界面。
  • 添加平滑的动画过渡效果提升用户体验。

🔧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 FAQCollapse

✅ 关键实现说明

1.状态管理

  • 使用useState<FAQItem[]>存储 FAQ 列表。
  • 每个FAQItem包含isOpen: boolean字段(通过扩展对象实现)。
  • 更新时使用不可变方式:setFaqList(prev => prev.map(...))

2.折叠切换逻辑

  • 点击整个问答标题区域即可切换(提升 UX)。
  • toggleOpen(id)只翻转对应项的isOpen状态。

3.动画实现(Tailwind + 条件渲染)

  • Vue 的<Transition>在 React 中没有直接等价物。
  • 我们采用条件渲染 + Tailwind 过渡类实现展开动画:
    {item.isOpen && <div className="transition-all duration-500 ease-in-out ...">...</div>}
  • 虽然无法完全复刻enter-from/leave-to的精细控制,但视觉效果非常接近。
  • 若需更复杂动画,可引入framer-motionreact-transition-group,但本场景无需。

4.样式与响应式

  • 使用max-w-2xl替代原w-2xl(Tailwind 中w-2xl不是标准类,应为max-w-2xl)。
  • 添加select-none防止用户误选+/-符号。
  • 整体保持深色文字(text-white),背景为bg-gray-500

5.内容优化

  • 将重复的 “What is Vue.js?” 改为不同问题,避免混淆(你可改回原内容)。

⚠️ 注意事项

  • 动画局限性:React 条件渲染在元素“消失”时会立即卸载,因此收起动画无法完全执行
    如果你希望收起也有动画,需使用heightopacity控制 +onTransitionEnd,或使用第三方库。

    ✅ 但对 FAQ 场景,展开有动画、收起瞬时隐藏是常见且可接受的设计。

  • 无障碍(a11y)建议(可选增强):

    • 为每个问答添加role="button"aria-expanded
    • 示例:
      <div role="button" aria-expanded={item.isOpen} tabIndex={0} onKeyDown={(e) => e.key === 'Enter' && toggleOpen(item.id)} >

🎨 TailwindCSS 样式重点讲解

🎯 TailwindCSS 样式说明
类名作用
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.tsxchildren数组中添加子路由

{ 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

每天造一个轮子,码力暴涨不是梦!🚀

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/25 20:09:24

《Mysql数据库应用》 第2版 郭文明 实验2 数据查询操作 答案

【实验2.1】字段查询&#xff08;1&#xff09;查询商品名称为“挡风玻璃”的商品信息。&#xff08;2&#xff09;查询ID为1的订单。1.查询用户ID为1的订单&#xff1a;2.查询订单ID为1的订单&#xff1a;【实验2.2】多条件查询查询所有促销的价格小于1000的商品信息。【实验2…

作者头像 李华
网站建设 2025/12/25 13:50:50

STM32居然能和服务器“聊天”?MQTT通信实现指南,小白也能看懂!

STM32居然能和服务器“聊天”&#xff1f;MQTT通信实现指南&#xff0c;小白也能看懂&#xff01; 你有没有想过&#xff1f;家里的温湿度传感器怎么把数据传给手机APP&#xff1f;智能灯怎么乖乖听从云端指令开关&#xff1f;其实背后藏着一个“通信小能手”——MQTT协议&…

作者头像 李华
网站建设 2025/12/29 8:20:34

PPT文件的两种不可编辑情况

不知道大家有没有遇到过&#xff0c;PPT文件无法编辑的情况&#xff0c;今天小编分享两种ppt文件不可编辑的原因以及解决方法。 情况一 如果打开ppt文件之后&#xff0c;发现幻灯片某些地方或者每张幻灯片同一个地方&#xff0c;无法编辑&#xff0c;这可能是因为PPT中设置了…

作者头像 李华
网站建设 2025/12/26 0:03:54

Excel文件中的保护工作表与工作簿的区别与应用

在Excel的日常使用中&#xff0c;数据的安全性和完整性至关重要。为了有效管理这些数据&#xff0c;Excel提供了多种保护机制&#xff0c;其中保护工作表和保护工作簿是两种常见的保护方式。虽然它们的目标都是保护数据&#xff0c;但具体的应用场景、保护范围及操作方式存在显…

作者头像 李华
网站建设 2025/12/29 6:20:48

python猫眼电影数据可视化与智能分析平台 数据大屏 电影票房预测 电影推荐(协同过滤推荐算法)爬虫flask框架

博主介绍&#xff1a;✌全网粉丝10W&#xff0c;前互联网大厂软件研发、集结硕博英豪成立软件开发工作室&#xff0c;专注于计算机相关专业项目实战6年之久&#xff0c;累计开发项目作品上万套。凭借丰富的经验与专业实力&#xff0c;已帮助成千上万的学生顺利毕业&#xff0c;…

作者头像 李华