前端组件库:别再重复造轮子了

前端组件库:别再重复造轮子了

毒舌时刻

这组件写得跟拼凑似的,一点都不统一。

各位前端同行,咱们今天聊聊前端组件库。别告诉我你还在手动编写所有组件,那感觉就像在没有工具的情况下盖房子——能盖,但效率低得可怜。

为什么你需要组件库

最近看到一个项目,每个组件都要手动编写,样式不统一,维护困难。我就想问:你是在做组件还是在做重复劳动?

反面教材

// 反面教材:手动编写组件 // Button.jsx import React from 'react'; function Button({ children, onClick }) { return ( <button onClick={onClick} style={{ padding: '10px 20px', backgroundColor: '#007bff', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }} > {children} </button> ); } export default Button; // Input.jsx import React from 'react'; function Input({ value, onChange, placeholder }) { return ( <input type="text" value={value} onChange={onChange} placeholder={placeholder} style={{ padding: '10px', border: '1px solid #ddd', borderRadius: '4px', width: '100%' }} /> ); } export default Input; // Card.jsx import React from 'react'; function Card({ children }) { return ( <div style={{ padding: '20px', border: '1px solid #ddd', borderRadius: '4px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }} > {children} </div> ); } export default Card; 

毒舌点评:这组件编写,就像在重复造轮子,每个组件都要手动编写样式,效率低得可怜。

正确姿势

1. Ant Design

// 正确姿势:Ant Design // 1. 安装依赖 // npm install antd // 2. 基本使用 import React from 'react'; import { Button, Input, Card, Form, Table, Modal, notification } from 'antd'; import 'antd/dist/reset.css'; function App() { const [isModalVisible, setIsModalVisible] = React.useState(false); const showModal = () => { setIsModalVisible(true); }; const handleOk = () => { setIsModalVisible(false); notification.success({ message: '成功', description: '操作成功', }); }; const handleCancel = () => { setIsModalVisible(false); }; const columns = [ { title: '姓名', dataIndex: 'name', key: 'name', }, { title: '年龄', dataIndex: 'age', key: 'age', }, { title: '操作', key: 'action', render: () => ( <Button type="primary">编辑</Button> ), }, ]; const data = [ { key: '1', name: '张三', age: 32, }, { key: '2', name: '李四', age: 42, }, ]; return ( <div style={{ padding: '20px' }}> <Card title="用户管理"> <Button type="primary" onClick={showModal} style={{ marginBottom: '20px' }}> 添加用户 </Button> <Table columns={columns} dataSource={data} /> </Card> <Modal title="添加用户" open={isModalVisible} onOk={handleOk} onCancel={handleCancel} > <Form> <Form.Item label="姓名" name="name" rules={[{ required: true, message: '请输入姓名' }]} > <Input placeholder="请输入姓名" /> </Form.Item> <Form.Item label="年龄" name="age" rules={[{ required: true, message: '请输入年龄' }]} > <Input type="number" placeholder="请输入年龄" /> </Form.Item> </Form> </Modal> </div> ); } export default App; 

2. Material UI

// 正确姿势:Material UI // 1. 安装依赖 // npm install @mui/material @emotion/react @emotion/styled // 2. 基本使用 import React from 'react'; import { Button, TextField, Card, CardContent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Modal, Box } from '@mui/material'; function App() { const [isModalVisible, setIsModalVisible] = React.useState(false); const [name, setName] = React.useState(''); const [age, setAge] = React.useState(''); const showModal = () => { setIsModalVisible(true); }; const handleClose = () => { setIsModalVisible(false); }; const handleSubmit = () => { console.log('提交:', { name, age }); setIsModalVisible(false); }; const rows = [ { id: 1, name: '张三', age: 32 }, { id: 2, name: '李四', age: 42 }, ]; return ( <div style={{ padding: '20px' }}> <Card sx={{ mb: 2 }}> <CardContent> <Button variant="contained" color="primary" onClick={showModal} sx={{ mb: 2 }} > 添加用户 </Button> <TableContainer component={Paper}> <Table> <TableHead> <TableRow> <TableCell>姓名</TableCell> <TableCell>年龄</TableCell> <TableCell>操作</TableCell> </TableRow> </TableHead> <TableBody> {rows.map((row) => ( <TableRow key={row.id}> <TableCell>{row.name}</TableCell> <TableCell>{row.age}</TableCell> <TableCell> <Button variant="outlined" color="primary"> 编辑 </Button> </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> </CardContent> </Card> <Modal open={isModalVisible} onClose={handleClose} aria-labelledby="modal-modal-title" aria-describedby="modal-modal-description" > <Box sx={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: 400, bgcolor: 'background.paper', border: '2px solid #000', boxShadow: 24, p: 4, }}> <h2>添加用户</h2> <TextField label="姓名" fullWidth value={name} onChange={(e) => setName(e.target.value)} /> <TextField label="年龄" type="number" fullWidth value={age} onChange={(e) => setAge(e.target.value)} /> <Box sx={{ mt: 2, display: 'flex', justifyContent: 'flex-end', gap: 1 }}> <Button onClick={handleClose}>取消</Button> <Button variant="contained" color="primary" onClick={handleSubmit}> 提交 </Button> </Box> </Box> </Modal> </div> ); } export default App; 

3. Tailwind CSS + Shadcn UI

// 正确姿势:Tailwind CSS + Shadcn UI // 1. 安装依赖 // npm install -D tailwindcss postcss autoprefixer // npx tailwindcss init -p // npx shadcn@latest init // 2. 配置 Tailwind CSS // tailwind.config.js /** @type {import('tailwindcss').Config} */ export default { content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], } // 3. 基本使用 import React from 'react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableRow } from '@/components/ui/table'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; function App() { const rows = [ { id: 1, name: '张三', age: 32 }, { id: 2, name: '李四', age: 42 }, ]; return ( <div className="p-4"> <Card className="mb-4"> <CardHeader> <CardTitle>用户管理</CardTitle> </CardHeader> <CardContent> <Dialog> <DialogTrigger asChild> <Button className="mb-4">添加用户</Button> </DialogTrigger> <DialogContent className="sm:max-w-md"> <DialogHeader> <DialogTitle>添加用户</DialogTitle> </DialogHeader> <div className="grid gap-4 py-4"> <div className="grid gap-2"> <Label htmlFor="name">姓名</Label> <Input placeholder="请输入姓名" /> </div> <div className="grid gap-2"> <Label htmlFor="age">年龄</Label> <Input type="number" placeholder="请输入年龄" /> </div> </div> <div className="flex justify-end gap-2"> <Button variant="secondary">取消</Button> <Button>提交</Button> </div> </DialogContent> </Dialog> <div className="overflow-auto"> <Table> <TableHead> <TableRow> <TableCell>姓名</TableCell> <TableCell>年龄</TableCell> <TableCell>操作</TableCell> </TableRow> </TableHead> <TableBody> {rows.map((row) => ( <TableRow key={row.id}> <TableCell>{row.name}</TableCell> <TableCell>{row.age}</TableCell> <TableCell> <Button variant="secondary">编辑</Button> </TableCell> </TableRow> ))} </TableBody> </Table> </div> </CardContent> </Card> </div> ); } export default App; 

毒舌点评:这才叫前端组件库,统一的样式,丰富的组件,开发效率高,再也不用担心重复造轮子的问题了。

Read more

深入剖析WebSphere反序列化漏洞CVE-2015-7450:从原理到实战利用

1. WebSphere反序列化漏洞初探 第一次听说WebSphere反序列化漏洞时,我正蹲在机房调试服务器。同事突然拍我肩膀说:"老李,咱们用的WebSphere好像有个能远程执行代码的洞!"当时我手里的咖啡差点洒在键盘上。这个编号CVE-2015-7450的漏洞,可以说是企业级Java应用的噩梦。 WebSphere作为IBM的旗舰中间件产品,广泛应用于银行、电信等关键行业。它本质上是个巨无霸级的Java EE容器,负责处理企业应用的核心业务逻辑。而漏洞就藏在它的SOAP通信接口里——攻击者只需要发送特制的序列化数据,就能让服务器执行任意命令,就像把后门钥匙直接递给黑客。 我后来在测试环境复现时发现,受影响的主要是7.0和8.5版本。想象一下,攻击者通过8880端口发送个精心构造的XML报文,就能在服务器上为所欲为。这可比普通的Web漏洞危险多了,因为WebSphere通常部署在内网核心区域,一旦突破就等于拿到了整个系统的控制权。 2. 漏洞原理深度解析 2.1 反序列化的潘多拉魔盒 要理解这个漏洞,得先搞懂Java反序列化是怎么回事。简单说,序列化是把对象变成字节流

GitHub 热榜项目 · 日榜精选(2026-01-08) | claude-mem、googletest、web-check等 | AI Agent、Web 分析、开发工具等

GitHub 热榜项目 · 日榜精选(2026-01-08) | claude-mem、googletest、web-check等 | AI Agent、Web 分析、开发工具等

🌟 GitHub 热榜项目 · 日榜精选(2026-01-08) | AI Agent、Web 分析、开发工具 🌟 📅 热榜时间:2026-01-08 🏷️ 核心标签:#GitHub #开源项目 #AI #Agent #开发工具 #效率工具 📊 统计摘要:本次共收录热门开源项目 10 个 | 榜单类型:日榜趋势 🎯 本期热点趋势洞察概述 当前 GitHub 实时热榜主要集中在 AI Agent 工程化 与 开发效率工具 两大方向: * Claude / AI Agent 相关项目持续升温,围绕「记忆系统、自动推理、工程落地」展开; * 网站分析、系统增强、公共 API 等实用型工具长期占据榜单; * 成熟基础设施项目(protobuf、

前端部署:从开发到生产的最后一公里

前端部署:从开发到生产的最后一公里 毒舌时刻 前端部署?这不是运维的事吗? "我只负责写代码,部署交给运维"——结果部署失败,互相甩锅, "我直接把文件上传到服务器"——结果更新不及时,缓存问题频发, "我用FTP上传,多简单"——结果文件传丢,网站崩溃。 醒醒吧,前端部署是前端开发的重要环节,不是别人的事! 为什么你需要这个? * 快速上线:自动化部署,减少人工操作 * 环境一致性:确保开发、测试、生产环境一致 * 回滚能力:出现问题时可以快速回滚 * 监控和日志:实时监控网站状态和错误 反面教材 # 反面教材:手动部署 # 1. 本地构建 npm run build # 2. 手动上传文件 ftp ftp://example.

前端小案例——网页井字棋

前端小案例——网页井字棋

前言:我们在学习完了HTML、CSS和JavaScript之后,就会想着使用这三个东西去做一些小案例,不过又没有什么好的案例让我们去练手,本篇文章就提供里一个案例——网页井字棋。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-ZEEKLOG博客 目录 写在前面         ——该案例的全部代码已经放在文章末尾,有兴趣的读者可以到最后将全部代码复制到自己的编译器上运行,感受一下井字棋案例的最终效果!!! ——首先先让我们了解一下我们需要了解的前置知识: 1.HTML骨架 2.CSS装饰 1. 引入字体和全局样式 2.设置 body 样式 3 设置 .wrapper 样式 4.设置 .current-status 和其中的元素样式  5.设置 board 和 .cell 样式 6.鼠标悬浮时的图片效果 7.设置 game-end-overlay 样式 8 设置 .winning-message 样式 9.