跳到主要内容
前端开发:避免重复造轮子,选用成熟组件库 | 极客日志
JavaScript 大前端
前端开发:避免重复造轮子,选用成熟组件库 综述由AI生成 探讨了前端开发中组件库的重要性,对比了手动编写组件与使用成熟库(如 Ant Design、Material UI、Shadcn UI)的差异。文章指出手动编写存在样式不统一、维护困难等问题,而使用组件库能显著提升开发效率和代码一致性。通过具体代码示例,展示了主流方案的最佳实践,建议开发者优先采用现有生态以避免重复造轮子。
菩提 发布于 2026/4/5 更新于 2026/5/22 23 浏览前端开发:避免重复造轮子,选用成熟组件库
背景与问题
这组件写得跟拼凑似的,一点都不统一。
各位前端同行,咱们今天聊聊前端组件库。别告诉我你还在手动编写所有组件,那感觉就像在没有工具的情况下盖房子——能盖,但效率低得可怜。
为什么你需要组件库
最近看到一个项目,每个组件都要手动编写,样式不统一,维护困难。我就想问:你是在做组件还是在做重复劳动?
反面教材
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 ;
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
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
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 = = = , ' ' }]}>
);
}
export default App ;
2. Material UI
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} >
{row.name}
{row.age}
编辑
))}
添加用户
setName(e.target.value)} />
setAge(e.target.value)} />
取消
提交
);
}
export default App ;
3. Tailwind CSS + Shadcn UI
export default {
content : ["./index.html" , "./src/**/*.{js,ts,jsx,tsx}" ],
theme : { extend : {} },
plugins : [],
};
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 = />
年龄
取消
提交
姓名
年龄
操作
{rows.map((row) => (
{row.name}
{row.age}
编辑
))}
);
}
export default App ;
分析与总结 :这才是前端组件库的正确用法,统一的样式,丰富的组件,开发效率高,再也不用担心重复造轮子的问题了。
label
"年龄"
name
"age"
rules
{[{
required:
true
message:
请输入年龄
<Input type ="number" placeholder ="请输入年龄" />
</Form.Item >
</Form >
</Modal >
</div >
<TableCell >
</TableCell >
<TableCell >
</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) =>
<TextField label ="年龄" type ="number" fullWidth value ={age} onChange ={(e) =>
<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 >
"请输入姓名"
</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 >
<TableRow key ={row.id} >
<TableCell >
</TableCell >
<TableCell >
</TableCell >
<TableCell >
<Button variant ="secondary" >
</Button >
</TableCell >
</TableRow >
</TableBody >
</Table >
</div >
</CardContent >
</Card >
</div >
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online