大家好,我是小杨,一个做了6年前端的老司机。今天想和大家聊聊组件封装的那些事儿 - 怎么设计组件既好用又灵活,特别是当用户想在组件里加自己的东西时,我们该怎么应对?
一、组件设计的基本考量
封装一个组件就像做一道菜,既要考虑味道(功能),也要考虑食客的口味(使用者需求)。我通常会从这几个方面思考:
- 功能完整性:组件要能独立完成它的核心任务
- API简洁性:props和事件不宜过多,命名要直观
- 可定制性:颜色、尺寸等基础样式应该可以调整
- 兼容性:能适应不同使用场景
- 性能:避免不必要的渲染
举个栗子,我封装一个简单的按钮组件:
jsx
function MyButton({
type = 'primary',
size = 'medium',
onClick,
children
}) {
const classNames = `my-btn ${type} ${size}`;
return (
<button className={classNames} onClick={onClick}>
{children}
</button>
);
}
// 使用
<MyButton type="danger" size="large" onClick={handleClick}>
删除
</MyButton>
二、如何支持用户自定义内容?
这才是今天的重头戏!用户用着用着就会说:"小杨啊,你这组件不错,但我还想在里面加个图标/提示文字/额外按钮..."
这时候怎么办?几种方案供你选择:
1. 使用children属性(最简单)
jsx
function MyCard({ title, children }) {
return (
<div className="my-card">
<h3>{title}</h3>
<div className="card-content">
{children} {/* 这里是用户自定义内容 */}
</div>
</div>
);
}
// 使用
<MyCard title="用户信息">
<p>姓名:我</p>
<button onClick={handleEdit}>编辑</button> {/* 用户加的按钮 */}
</MyCard>
2. 使用render props(更灵活)
jsx
function MyList({ data, renderItem }) {
return (
<ul className="my-list">
{data.map((item, index) => (
<li key={index}>
{renderItem(item, index)}
</li>
))}
</ul>
);
}
// 使用
<MyList
data={users}
renderItem={(user) => (
<>
<span>{user.name}</span>
<button onClick={() => handleDelete(user.id)}>删除</button>
</>
)}
/>
3. 预留插槽(Vue中的概念,React也可以用)
jsx
function MyComponent({ header, footer, children }) {
return (
<div className="my-component">
{header && <div className="header">{header}</div>}
<div className="content">{children}</div>
{footer && <div className="footer">{footer}</div>}
</div>
);
}
// 使用
<MyComponent
header={<h2>自定义标题</h2>}
footer={<button onClick={handleSubmit}>提交</button>}
>
主要内容
</MyComponent>
三、高级技巧:组件组合
有时候,把一个大组件拆成几个小组件,让用户自由组合会更灵活:
jsx
function MyForm({ children }) {
return <form className="my-form">{children}</form>;
}
function MyFormItem({ label, children }) {
return (
<div className="form-item">
<label>{label}</label>
{children}
</div>
);
}
// 使用
<MyForm>
<MyFormItem label="用户名">
<input type="text" />
<button type="button" onClick={checkDuplicate}>检查重复</button>
</MyFormItem>
<MyFormItem label="密码">
<input type="password" />
</MyFormItem>
</MyForm>
四、实战经验分享
- 命名很重要 :像
extraContent
、customFooter
这种名字比content1
、content2
友好多了 - 文档要写清楚:哪些地方可以插入自定义内容,插入的内容会受到什么限制
- 提供默认内容:给自定义props设置合理的默认值
- 样式处理:确保用户插入的内容不会破坏组件样式结构
- 性能考虑:如果自定义内容很复杂,考虑使用memo优化
jsx
const MemoizedComponent = React.memo(function({ content }) {
return <div>{content}</div>;
});
五、总结
好的组件设计就像乐高积木 - 本身结构完整,又能和其他积木灵活组合。记住三个原则:
- 开放封闭原则:对扩展开放,对修改封闭
- 单一职责原则:一个组件只做一件事
- 最少知识原则:组件不需要知道太多外部信息
希望这些经验对你有帮助!如果你有更好的组件设计思路,欢迎在评论区交流~
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!