← 返回博客

把组件从「数据驱动」重构成「容器壳驱动」

2026-08-24·iOS / 架构·约 2 分钟

做组件库最容易踩的坑,是把组件设计得「太懂业务」。

我们的 YBList 最早是数据模型驱动的:定义一个 YBListItemModel,里面塞满了 titlesubtitlerightTextshowArrowswitchOn……组件内部根据这些字段决定渲染什么。

一开始很爽,业务方三行代码就能出一个设置页。

然后就崩了

第一个需求来了:右侧要放一个自定义的角标。加个 badgeText 字段。

第二个需求:角标要能带图片。加 badgeImage

第三个:右侧是个下拉选择器,展开后有动画。

到这里 model 已经有 14 个字段,组件内部是一坨 if-else,而且每加一个字段,所有已接入的业务都要重新回归一遍。组件成了瓶颈,而不是加速器。

换个思路

问题的根源在于:组件试图穷举业务的所有可能性。而业务的可能性是无穷的。

所以换成容器壳(slot)驱动 —— 组件只负责三件事:

  1. 定义布局骨架(左侧标题区、右侧内容区)
  2. 管理约束关系和间距规则
  3. 提供一个空的容器,业务爱塞什么塞什么
// Before:组件决定渲染什么
model.rightText = @"已开启";
model.showArrow = YES;
[cell configWithModel:model];

// After:业务决定渲染什么,组件只管布局
cell.titleText = @"消息通知";
cell.subtitleText = @"接收新消息提醒";
[cell setRightContentView:myCustomView];  // 想放啥放啥

组件代码量少了 40%,if-else 全没了。

布局才是真正要解决的问题

放开内容之后,唯一需要严格约束的反而是布局规则。我们的规定很简单:

[self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
                                                 forAxis:UILayoutConstraintAxisHorizontal];
[self.rightContainer setContentCompressionResistancePriority:UILayoutPriorityRequired
                                                     forAxis:UILayoutConstraintAxisHorizontal];

就这三条规则,覆盖了目前所有业务场景,包括那些当初逼我加字段的需求。

一点体会

好的组件 API 不是「提供更多能力」,而是「明确更少的职责」。

数据驱动的问题不在于数据,而在于组件把「渲染决策」也接了过来。而渲染决策天然属于业务。组件应该只做业务做不了、或者每个业务都要重复做的那部分 —— 在这个例子里,就是布局约束。

顺带一个收获:字段变少之后,动态字体(我们支持 5 级缩放)的适配成本也降了,因为不再需要为每种 if-else 分支单独验证一遍布局。