news 2026/1/29 12:48:53

50天50个小项目 (React19 + Tailwindcss V4) ✨| RandomChoicePicker(标签生成)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
50天50个小项目 (React19 + Tailwindcss V4) ✨| RandomChoicePicker(标签生成)

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

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

构建一个简单的标签输入组件。用户可以在文本框中输入多个选项,并通过逗号分隔,组件会自动将其拆分成可视化的“标签”展示出来。

🌀 组件目标

  • 接收用户输入的一段文本。
  • 使用逗号,分割输入内容。
  • 动态渲染为一组“标签”(Tag)。
  • 使用 TailwindCSS 快速构建美观现代的 UI 界面。
  • 提供清晰的交互反馈。

🔧RandomChoicePicker.tsx 组件实现

import React, { useState, useEffect } from 'react' const RandomChoicePicker: React.FC = () => { const [textareaText, setTextareaText] = useState<string>('') const [tagList, setTagList] = useState<string[]>([]) // 每当 textareaText 变化时,自动分割标签 useEffect(() => { const tags = textareaText .split(',') .map((item) => item.trim()) // 去除前后空格 .filter((item) => item !== '') // 过滤空字符串 setTagList(tags) }, [textareaText]) return ( <div className="flex h-screen items-center justify-center"> <div className="w-full max-w-2xl rounded-2xl bg-gray-400 p-8 shadow-lg"> <h3 className="font-mono text-2xl text-gray-800"> Enter all of the choices divided by a comma (',').(输入所有选项,并用英文逗号,分隔) <br /> Press enter when you're done </h3> <textarea className="my-4 h-36 w-full resize-none rounded-lg bg-gray-200 p-4 text-gray-800 placeholder-gray-500 focus:ring-2 focus:ring-blue-300 focus:outline-none" placeholder="Enter choices here..." value={textareaText} onChange={(e) => setTextareaText(e.target.value)} /> {tagList.length > 0 && ( <div className="mt-4 flex flex-wrap gap-2"> {tagList.map((item, index) => ( <div key={`${item}-${index}`} // 使用 index 避免重复 key(因 item 可能重复) className="rounded-2xl bg-amber-200 px-3 py-1 text-sm font-medium text-gray-800"> {item} </div> ))} </div> )} </div> <div className="absolute right-20 bottom-10 text-red-500">CSDN@Hao_Harrision</div> </div> ) } export default RandomChoicePicker

✅ 关键实现说明

功能Vue 实现React + TS 实现
双向绑定文本域v-model="textareaText"value + onChange控制
自动分割逗号内容watchEffect+splitTag()useEffect监听textareaText
标签渲染v-for="item in tagList"{tagList.map(...)}
空值过滤无(原逻辑会保留空字符串)✅ 添加.trim()filter(item !== '')提升体验

🛠️ 改进细节

  1. 去重与清理

    • 使用.trim()去除每个选项前后的空格(如" apple ""apple")。
    • 过滤掉空字符串,避免显示空白标签。
  2. Key 策略

    • 因用户可能输入重复项(如"A, A, B"),不能仅用item作 key。
    • 改为key={item−{index}}确保唯一性,避免 React 警告。
  3. UI/UX 增强

    • 添加resize-none禁止手动调整 textarea 大小(保持布局稳定)。
    • 添加focus:ring提升交互反馈。
    • 使用flex-wrap确保标签在小屏换行。
    • 添加bg-gray-100背景色提升整体可读性。
  4. 类型安全

    • textareaText: string
    • tagList: string[]

📌 注意事项

  • 此组件目前只负责输入和解析,不包含“随机选择”逻辑(如抽一个标签)。如果你后续需要“Pick Random”功能,可以在此基础上加一个按钮调用:
    const pickRandom = () => { if (tagList.length > 0) { const random = tagList[Math.floor(Math.random() * tagList.length)]; alert(`Selected: ${random}`); } };

🎨 TailwindCSS 样式重点讲解

🎯 TailwindCSS 样式说明
类名作用
flex,items-center,justify-center居中布局整个容器
h-screen容器高度为视口全高
rounded-2xl圆角大小为 1rem
bg-gray-400bg-gray-200bg-amber-200设置背景颜色
p-8,p-4,p-1不同层级的内边距
my-4上下外边距为 1rem
w-full宽度为 100%
h-36高度为 9rem
text-2xl字体大小为 1.5rem
font-mono使用等宽字体
gap-2flex 子元素之间间隔为 0.5rem
h-8高度为 2rem
rounded-2xl圆角为 1rem

这些类名帮助我们快速构建出一个居中的响应式布局,并确保视觉上的一致性和美观性。

🦌 路由组件 + 常量定义

router/index.tsxchildren数组中添加子路由

{ path: '/', element: <App />, children: [ ... { path: '/RandomChoicePicker', lazy: () =>import('@/projects/RandomChoicePicker.tsx').then((mod) => ({ Component: mod.default, })), }, ], },

constants/index.tsx 添加组件预览常量

import demo13Imgfrom '@/assets/pic-demo/demo-13.png' 省略部分.... export const projectList: ProjectItem[] = [ 省略部分.... { id: 13, title: 'Random Choice Picker', image: demo13Img, link: 'RandomChoicePicker', }, ]

🚀 小结

作为表单组件的一部分,用于收集用户输入的多项数据。

📅 明日预告: 我们将完成AnimatedNavigation组件,一个非常有意思的动画的导航组件!🚀


原文链接:https://blog.csdn.net/qq_44808710/article/details/148615314

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

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

CppCon 2024 学习:Fast and small C++ Whenefficiency matters

执行方式&#xff1a; 程序执行&#xff1a; 示例显示了程序的执行命令&#xff1a;$ ./a.out。这里使用的是 Linux 风格的命令行执行&#xff0c;其中没有指定输出文件名&#xff0c;因此程序默认的输出文件名为 a.out。这是 Unix 和类 Unix 系统中默认的可执行文件名称。 …

作者头像 李华
网站建设 2026/1/29 2:47:39

别再把数据管道当“体力活”了:从单体任务到事件驱动的升级之路

别再把数据管道当“体力活”了&#xff1a;从单体任务到事件驱动的升级之路 作者&#xff1a;Echo_Wish兄弟们&#xff0c;咱们今天聊点“掏心窝子”的大数据经验&#xff1a;现代数据管道到底应该怎么设计&#xff1f; 很多公司到现在还在用“单体式任务管道”——Airflow 一堆…

作者头像 李华
网站建设 2026/1/28 2:23:19

【面试现场】谢飞机大战Java面试官:从基础到架构的爆笑面试实录

【面试现场】谢飞机大战Java面试官&#xff1a;从基础到架构的爆笑面试实录 第一轮&#xff1a;Java基础与集合框架 面试官&#xff1a;谢飞机同学&#xff0c;你好。我是今天的面试官&#xff0c;我们开始第一轮技术面试。首先问个基础问题&#xff1a;Java中ArrayList和Linke…

作者头像 李华
网站建设 2026/1/26 17:32:32

2025.12.11总结

工作日精进&#xff1a;明天版本过点&#xff0c;今晚每个人都搞得很晚&#xff0c;我也是晚上11&#xff1a;30才回到租房。每天就这么起床&#xff0c;上班&#xff0c;吃饭&#xff0c;下班。租房&#xff0c;工位&#xff0c;食堂&#xff0c;三点一线。下班后&#xff0c;…

作者头像 李华