宜搭自定义页面信息密度设计规范
核心定位
信息密度是页面密度配置。DENSITY_CONFIG、场景选择、移动端降级和无障碍要求对自定义页面都适用;实现示例使用 React hooks。
维护已检测到的 .oyd.jsx / .oyb.jsx / renderJsx / 平台 Jsx 组件页面时,才参考 didMount / this.utils.isMobile() 的平台 JSX 组件写法。
严格要求
- 每次生成列表/表格类自定义页面时都考虑密度,无需用户主动提及。
- PC 列表/表格默认
comfortable,可提供紧凑/舒适切换。 - 移动端固定
spacious,不显示密度切换 UI。 - 固定展示大屏使用
spacious,不显示密度切换 UI。 - 表单填写页交原生表单;若只讨论密度,固定
comfortable,不提供切换。 - 间距、字号、行高、控件高度统一从密度 token 派生,避免散落魔法值。
- 密度状态是页面本地状态,不依赖跨会话 memory。
场景选择
| 场景 | 默认密度 | 切换 UI |
|---|---|---|
| 专业后台、运营列表、大数据表格 | compact 或 comfortable | PC 提供 |
| 常规任务管理、审批列表 | comfortable | PC 提供 |
| 引导页、展示页、固定大屏 | spacious | 不提供 |
| 移动端 | spacious | 不提供 |
| 原生表单填写 | comfortable | 不提供 |
用户明确说“紧凑/密集/一屏更多”时选 compact;说“宽松/大字体/更易读”时选 spacious。用户未指定时按页面类型和设备选择。
密度 token
同一页面可以把数值映射成 CSS variables、antd token 或 inline style;关键是所有相关组件都消费同一个配置。
javascriptconst DENSITY_CONFIG = { compact: { cardPadding: '8px 12px', fontSize: 12, lineHeight: 1.4, tableRowHeight: 32, controlHeight: 24, sectionGap: 8, }, comfortable: { cardPadding: '16px 20px', fontSize: 14, lineHeight: 1.6, tableRowHeight: 48, controlHeight: 32, sectionGap: 16, }, spacious: { cardPadding: '24px 28px', fontSize: 16, lineHeight: 1.8, tableRowHeight: 64, controlHeight: 40, sectionGap: 24, }, };
React Hooks 实现
在 Canvas 中分别处理密度选择和布局宽度:
matchMedia+ hooks 监听浏览器视口或输入方式的变化。下方示例用视口宽度切换密度;触控能力按对应媒体条件判断。- 页面分栏、筛选栏和主辅面板按实际内容容器宽度重排,iframe、侧栏或抽屉均读取自身可用空间。
- 按 共享响应式规则 优先用 CSS 重排。需要参考时执行
openyida sample openyida-page-template canvas-responsive-layout,按需复用布局片段;组件需要读取实际宽度时,再复用带清理的测量 Hook,持续响应容器变化。
jsximport React, { useEffect, useMemo, useState } from 'react'; function useIsMobile() { const query = '(max-width: 767px)'; const [isMobile, setIsMobile] = useState( () => window.matchMedia(query).matches, ); useEffect(() => { const media = window.matchMedia(query); const handleChange = (event) => setIsMobile(event.matches); media.addEventListener('change', handleChange); return () => media.removeEventListener('change', handleChange); }, []); return isMobile; } function DensityAwareList() { const isMobile = useIsMobile(); const [desktopDensity, setDesktopDensity] = useState('comfortable'); const density = isMobile ? 'spacious' : desktopDensity; const tokens = useMemo(() => DENSITY_CONFIG[density], [density]); return ( <section style={{ '--row-height': `${tokens.tableRowHeight}px` }}> {!isMobile && ( <DensitySwitch value={desktopDensity} onChange={setDesktopDensity} /> )} <BusinessTable density={density} tokens={tokens} /> </section> ); }
如果目标使用 antd Table / ConfigProvider,把密度映射到 size 和组件 token,同时保留业务级 DENSITY_CONFIG 作为唯一来源;不要一部分走 size="small"、另一部分继续写固定 padding。
响应式纪律
- 移动端自动使用
spacious,回到桌面后恢复用户先前选择的桌面密度。 - 切换密度不能清空筛选、分页、选中行和数据。
- 触控目标仍需满足可点击尺寸;
compact只用于桌面高密度场景。 - 系统字体缩放、长中文、英文和大数值下均不得截断关键字段。
- 虚拟表格行高、骨架屏行高和真实行高必须使用同一密度 token。
平台 JSX 组件维护注意事项
已有普通自定义页面可以继续使用:
javascriptexport function didMount() { if (this.utils.isMobile()) { _customState.density = 'spacious'; this.forceUpdate(); } }
这段只用于平台 JSX 组件页面或 native 页面维护。React hooks 实现不得使用 didMount、this.utils.isMobile()、_customState 或 forceUpdate;应使用上面的 matchMedia hook 并 cleanup。
现有普通页面只能作为 native 兼容参考,不能据此改变当前页面的实现事实。
异常处理
| 场景 | 处理 |
|---|---|
| 切换后局部样式没变 | 检查是否仍有硬编码 padding/height,统一消费 token |
| 移动端还显示切换 UI | 由 isMobile 派生 UI 和最终 density,不只改样式 |
| 回桌面后丢失用户选择 | 分开保存 desktopDensity 与派生 density |
| 字体放大后内容裁切 | 避免固定内容高度,允许行高/单元格扩展 |
| 配置缺失 | 回退 comfortable,同时暴露开发期错误 |
写操作边界
本技能负责生成规范,不自动授权发布。真实发布前必须展示代码/配置摘要并获得用户确认;发布后提供页面 URL 与 PC/移动端验证结果。
验收清单
- 页面类型与默认密度匹配。
- Canvas 示例优先;普通页生命周期只出现在 legacy 小节。
- PC 切换真实改变表格/卡片/控件密度,不丢业务状态。
- 移动端固定
spacious且隐藏切换 UI。 - 所有密度相关值来自统一 token。
matchMedia监听或其他响应式副作用有 cleanup。- 桌面宽视口中的窄 iframe、侧栏和抽屉按自身宽度重排;分别验证设备对应的密度和容器对应的布局。


