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

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

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

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

🌀 组件目标

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

🔧 RandomChoicePicker.tsx 组件实现

TypeScript 复制代码
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 样式重点讲解

类名 作用
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-2 flex 子元素之间间隔为 0.5rem
h-8 高度为 2rem
rounded-2xl 圆角为 1rem
[🎯 TailwindCSS 样式说明]

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

🦌 路由组件 + 常量定义

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

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

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

TypeScript 复制代码
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

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

相关推荐
浮游本尊2 小时前
React 18.x 学习计划 - 第九天:React 18高级特性和最佳实践
前端·学习·react.js
诸神缄默不语2 小时前
用Vite创建Vue3前端项目
前端·vite·cue3
旧梦吟2 小时前
脚本 生成图片水印
前端·数据库·算法·golang·html5
How_doyou_do2 小时前
模态框与DOM,及React和Vue中的优化
前端·vue.js·react.js
前端不太难2 小时前
RN 的导航体系太混乱,如何选型和架构设计?
前端·react native·架构
....4922 小时前
el-select 下拉框支持线上 SVG + 本地图片图标 展示
前端·javascript·vue.js
Hao_Harrision2 小时前
50天50个小项目 (React19 + Tailwindcss V4) ✨| FAQ Collapse(问题解答折叠面板)
前端·typescript·react·vite7·tailwildcss
Youyzq3 小时前
css样式用flex 布局的时候元素尺寸展示不对
前端·javascript·css
cc蒲公英3 小时前
less和sass区别
前端·less·sass