R1.11.3parent-child composition constraints设计

合法的父子搭配需要显式约束

别名: 复合约束 · 合法子节点 · compound constraints · allowed children

概念解释

树默认允许任意节点互相嵌套。设计系统里的父子却不是任意的:选项只能放进选择器,列头只能放进表格,菜单项只能放进菜单。父子搭配约束(parent-child composition constraints)把「谁可以做谁的孩子」写成可被检查的规则,而不是写在说明文字里等人记。合法搭配被显式化之后,非法嵌套在编辑和构建时就被拒绝,而不是渲染出一块看起来像、行为却对不上的控件。

约束的对象是角色,不是类名字符串。<Select> 接受 <Select.Option>,不接受随便一个 <div> 冒充选项——即使那个 div 画得一模一样。画得像不能代替「我是选项」这条契约。

机制

开放组合的默认值来自通用 UI 树:浏览器和框架都允许几乎任何元素互套。设计系统的组件却共享内部协议:选中态往上冒泡、键盘方向键在兄弟间移动、当前项 id 写回父级。没有协议的节点走进这棵树,父级读不到约定字段,子级也收不到「你在列表第几项」的信号。画面可能还能拼出来,状态和键盘已经断了。

口头约定拦不住复制粘贴。显式约束把协议提升为类型、运行时断言或 HTML 内容模型:父级的子类型白名单、子级对父级上下文的必需声明。检查发生在调用点闭合的那一刻——正是组合空间真正被使用的地方。说明文字发生在调用点之外,读到的人与写错的人往往不是同一个。

边界

真正通用的布局容器(栈、网格)必须接受任意子节点,对它们加白名单等于禁止排版。跨系统嵌入的第三方小部件无法参与内部协议,约束应退到外壳,而不是假装它是合法子项。约束过窄会把合理的扩展(在选项里嵌一套自定义内容)误判为非法;过宽又回到「看起来像就行」。外观档位之间的选择,不是父子合法性问题。

怎么落地

  • 为每个复合体写一张允许表:父角色、合法子角色、是否允许多个、顺序是否有意义。表是接口的一部分,跟属性一同发布。
  • 用类型或静态检查落实允许表;做不到静态时,在开发构建里对非法子节点抛错,并指出应收的父级。
  • 子组件在合法父级之外单独使用时必须失败,而不是静默画成「没选中、没键盘」的空壳。
  • 验证:写两份调用,一份把选项塞进菜单,一份把菜单项塞进选择器。两份都应在编辑器或构建期失败,且报错点名正确父级。再写一份合法嵌套,键盘方向键与选中态必须走通。若只有说明里写了「不要这样用」,而构建能通过,约束就还不存在。

延伸

  • 同组R1.11.1 插槽把内容的决定权交还给使用方 · R1.11.2 拼装比传参更少歧义 · R1.11.4 上下文传递让子组件适配所处容器
  • 相邻R1.02 组件库与变体 · R1.06 贡献流程与治理
  • 站内检索parent-child composition constraints · compound component · allowed children

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/R1.11.3