Masonry Gallery
Masonry Gallery 用于展示宽高比例不同的图片。图片保持各自比例,并依次放入当前最短的列;用户向下滚动页面时,控件自动加载下一页,不会在控件内部再出现一条独立滚动条。
它适合灵感图库、作品集、旅游照片、媒体素材和视觉案例,不等同于 CardSet。
| 控件 | 主要目标 | 数据与布局 |
|---|---|---|
| Masonry Gallery | 以图片为主,保留不同宽高比,连续浏览 | 分页图片记录 + 页面级无限滚动 |
| CardSet | 以业务记录摘要为主,可带状态、元数据和操作项 | 统一卡片模板 + Pagination 或 Load More |
| Grid | 手工组织页面区域和控件 | 固定的 24 列布局,不重复数据记录 |
1. 添加控件
- 进入 Page Designer,在左侧展开 Containers。
- 将 Masonry Gallery 拖入页面。
- 选中控件,在右侧先配置 Data Source,再完成字段映射。
- 为控件设置稳定名称,例如
portfolioGallery。
设计画布会显示不同宽高比的示意卡片。打开 Preview 后,控件才会读取真实数据;设计态最多自动读取两页,避免编辑页面时不断加载。
2. 配置数据源
Masonry Gallery 支持四种数据源:
| 数据源 | 适用场景 |
|---|---|
| Model Data Source | 展示 Spark 业务模型中的图片记录 |
| Custom API | 调用已有业务接口并自行映射字段 |
| Media Library | 通过统一媒体连接器读取媒体库或 DAM |
| Object Storage | 按 Bucket/Container 和目录读取 OSS、S3 或 MinIO 图片 |
2.1 Custom API 样例
本文的基础样例使用:
POST /spark/api/sample/masonry-gallery/images
在 Data Source 对话框中配置:
| 属性 | 示例值 |
|---|---|
| URL | /spark/api/sample/masonry-gallery/images |
| Request Method | POST |
| Rows Path | data.records |
| Total Path | data.total |
| Current Page Path | data.current |
| Page Size Path | data.pageSize |
点击 Test & Import 可请求一页数据并导入 Response Fields。样例字段为:
| Field Path | Data Type | 用途 |
|---|---|---|
id | TEXT | 记录唯一键 |
imageUrl | URL | 图片地址 |
title | TEXT | 图片标题 |
caption | TEXT | 补充说明 |
badge | TEXT | 分类标签 |
alt | TEXT | 图片替代文本 |
width | NUMBER | 图片原始宽度 |
height | NUMBER | 图片原始高度 |
请求体会包含分页信息:
{
"current": 1,
"pageSize": 6
}
推荐响应格式:
{
"success": true,
"data": {
"current": 1,
"pageSize": 6,
"total": 24,
"records": [
{
"id": "gallery-1",
"imageUrl": "/spark/api/sample/masonry-gallery/assets/coastal-architecture.jpg",
"title": "Coastal Geometry",
"caption": "Sunlit concrete forms above a quiet blue sea.",
"badge": "Architecture",
"alt": "White coastal architecture above the sea",
"width": 1200,
"height": 1200
}
]
}
}
total 最可靠。若接口不返回总数,当前页记录少于 Items Per Request 时,控件也会判断已经结束。Row Unique Key 必须在所有页面中保持唯一;重复键会被去重。
2.2 Media Library 与 Object Storage
这两类数据源先在 App Settings → Integrations → Media Connections 中建立连接:
- 在 Console 的 Secret Management 创建凭据。对象存储选择
OBJECT_STORAGE,媒体平台选择MEDIA_PROVIDER。 - 回到 Media Connections,选择 Provider 和 Secret。表单会根据 Provider 只显示确实需要的连接参数;自动使用的官方 Endpoint 不会显示。
- 在 Masonry Gallery 的 Data Source 中选择 Media Library 或 Object Storage,只引用 Connection,再填写 Collection/Container、Path、筛选和 Page Size。
- 点击 Test。测试、设计预览和运行态使用同一个媒体查询网关与响应解析逻辑。
当前正式可用的 Provider:
| Provider | Secret Management | Media Connection 参数 |
|---|---|---|
| Cloudinary | MEDIA_PROVIDER;API Key 填入 API Key,API Secret 填入 API Secret | Cloud Name 必填,Root Folder 可选 |
| ImageKit | MEDIA_PROVIDER;Public API Key 填入 API Key,Private API Key 填入 API Secret | Root Folder 可选;官方 API Endpoint 自动使用 |
| Aliyun OSS / AWS S3 / MinIO | OBJECT_STORAGE;填写 Access Key 与 Access Secret | Endpoint、默认 Bucket 和 Root Prefix 按存储配置填写 |
Spark Sample Media Library 仅用于不依赖外部账号的开发调试。Cloudinary 和 ImageKit 是正式 Media Library Connector;Bynder、AEM Assets 和完整 Spark Media Library 尚未开放。
页面 JSON 不保存 secretId、Access Key 或临时签名 URL。平台在后端根据 Connection 解析 Secret,并把供应商结果转换为统一记录:
{
"records": [{
"id": "asset-001",
"imageUrl": "https://cdn.example/full.webp",
"thumbnailUrl": "https://cdn.example/card.webp",
"title": "Summer campaign",
"alt": "Summer campaign launch",
"width": 1600,
"height": 1067
}],
"nextCursor": "opaque-next-cursor",
"hasMore": true,
"total": null
}
Masonry Gallery 使用 thumbnailUrl 显示卡片、使用 imageUrl 打开全屏预览,并以 nextCursor 连续加载。spark-sample 中的 SampleMasonryMediaConnector.java、masonry-gallery-media-connection.json 和 masonry-gallery-media-page.json 给出了无需外部凭据的完整案例。
3. 配置字段映射
| 控件属性 | 推荐映射 | 是否必需 |
|---|---|---|
| Row Unique Key | id | 是 |
| Image URL Field | imageUrl | 是 |
| Title Field | title | 否 |
| Caption Field | caption | 否 |
| Badge Field | badge | 否 |
| Alternative Text Field | alt | 建议配置 |
| Image Width Field | width | 建议配置 |
| Image Height Field | height | 建议配置 |
Width 与 Height 位于 Advanced。两者一起配置后,控件在图片下载前就能预留正确比例,减少页面跳动。若后台暂时无法提供尺寸,控件仍会在图片加载后重新排版。
Alternative Text 应描述图片内容,而不是重复文件名。缺少 alt 时会回退到 Title;两者都没有时使用空替代文本。
4. 配置响应式布局
| 属性 | 建议值 | 说明 |
|---|---|---|
| Desktop Columns | 4 | 宽屏列数 |
| Tablet Columns | 3 | 中等宽度列数 |
| Mobile Columns | 2 | 手机列数;长标题较多时可改为 1 |
| Spacing | DEFAULT | COMPACT、DEFAULT 或 RELAXED |
| Items Per Request | 6 或 12 | 单次加载数量 |
列数随页面宽度变化。图片不会被裁剪成相同高度;卡片会按照各自比例形成瀑布流。
5. 滚动加载
运行时使用页面本身的滚动位置。当用户距离当前内容末尾约一个半屏时,控件开始请求下一页:
- 同一时刻只发送一个分页请求。
- 加载中显示轻量骨架状态。
- 请求失败后暂停自动加载并显示 Retry。
- 数据结束后显示完成提示,不再请求。
- 返回刚离开的页面时,短时间内恢复已加载记录和滚动位置。
因此,不应把 Masonry Gallery 放入高度固定且带内部滚动条的窄容器。页面中若还有固定页脚,也应为图库末尾提示留出空间。
6. 全屏预览与交互
开启 Enable Fullscreen Preview 后,点击图片会打开全屏预览。用户可以使用:
- 左右按钮或方向键切换已经加载的图片
- Escape 关闭
- Tab 聚焦关闭和切换按钮
- Enter 或 Space 从聚焦卡片打开预览
如果还配置了整项 onClick,执行前控件会把记录写入 Current Record。后续动作可读取:
record.id
record.imageUrl
record.title
record.badge
一次点击可以同时打开预览并执行 onClick。如果交互会立即跳转页面,建议关闭 Fullscreen Preview,避免两个意图同时发生。
控件函数:
| 函数 | 用途 |
|---|---|
reloadGallery | 清空当前分页状态并从第一页重新请求 |
setGalleryData | 直接写入一组记录;写入后视为完整数据,不再自动翻页 |
7. 页面请求上下文与后端调试
Data Source 测试、设计预览和运行页面使用同一套请求构造与响应解析。平台自动添加:
| Header | 值 |
|---|---|
X-Spark-Page-Environment | DEV、TEST 或 PROD |
X-Spark-Page-Render-Mode | DESIGN_PREVIEW 或 RUNTIME |
Data Source 中不需要手工添加这两个 Header。后端可以在开发预览中返回较短的数据集,以便快速调试;运行态再返回完整内容。样例 Controller 使用共享 Header 常量与解析器:
@PostMapping
public ApiResult<ProTablePageResult<MasonryGalleryImageDTO>> queryByPost(
@RequestBody(required = false) MasonryGalleryQueryRequest request,
@RequestHeader(value = SparkPageRequestHeaders.ENVIRONMENT, required = false) String environment,
@RequestHeader(value = SparkPageRequestHeaders.RENDER_MODE, required = false) String renderMode) {
return SparkApiResultHelper.success(
Locale.ENGLISH,
galleryService.query(request,
SparkPageRequestHeaders.resolve(environment, renderMode)),
"SPARK-SAMPLE-MASONRY-GALLERY-0001");
}
Service 根据渲染模式选择数据规模:
int total = requestContext != null
&& requestContext.getRenderMode() == SparkPageRenderMode.DESIGN_PREVIEW
? 12
: 24;
实际样例代码位于 spark-sample:
gallery/web/MasonryGalleryController.java
gallery/service/MasonryGalleryService.java
resources/samples/masonry-gallery-page.json
resources/static/sample/masonry-gallery/
完整协议见 页面请求上下文与后端调试。
8. 性能与数据建议
- 返回适合当前展示宽度的图片,避免直接加载数十 MB 原图。
- 优先提供 WebP、AVIF 或经过压缩的 JPEG,并通过 CDN 或同源静态资源服务缓存。
- 始终提供稳定的
id、width、height和有意义的alt。 - 第一页建议 6–20 条;单页过大会推迟首屏完成时间。
- 后端排序必须稳定,否则不同页面可能重复或遗漏记录。
- 图片接口失败与数据接口失败应分开排查;单张图片失败只显示占位,不会中止后续分页。
9. 常见问题
一直重复加载同一批图片
确认后端使用请求中的 current 和 pageSize 做真实分页,并返回稳定 total。同时检查 data.current、data.pageSize 路径是否正确。
滚动后没有继续请求
检查是否已经达到 total,上一页记录数是否少于 Items Per Request,或上一次请求是否失败并等待 Retry。
图片加载后布局明显跳动
在响应中返回原始 width、height,并映射到 Image Width Field、Image Height Field。
图片显示为占位图
检查 Image URL Field、图片地址、认证和跨域策略。数据接口成功不代表图片地址一定可访问。
想展示业务按钮、状态操作和复杂元数据
使用 CardSet。Masonry Gallery 只负责图片优先的连续浏览,不提供 Card Actions。