SwGallery
SwGallery 是不滚动、换行铺成等高网格的封面卡容器,与 SwRail(横滚横排)互补。它只管布局与取数节奏——卡片一切视觉(封面 / 角标 / 评分 / 集数)由 #default 作用域插槽业务渲染(通常放 SwImage),影 / 漫 / 小说封面对组件无差别。
海报墙:minItemWidth 自适应列数 + 按钮加载更多(剩余计数)
加载中...
列数控制(二选一)
| 模式 | 写法 | 适用 |
|---|---|---|
| 定卡宽自适应(默认) | :min-item-width="180" | 海报墙:窗口缩放列数跟着变(CSS Grid auto-fill + minmax) |
| 锁定列数 | :columns="3" 或 :columns="{ mobile: 1, tablet: 2, desktop: 3 }" | 设计稿明确列数、超宽屏不许变(断点对齐 framework:mobile <768 / desktop ≥1024,缺档就近回退) |
两者纯 CSS 实现(media query + CSS 变量),零 JS、SSR 安全。columns 传了即覆盖 minItemWidth。
columns 断点锁定(1/2/3 列)+ 自定义 #load-more 按钮
加载中...
loadMode auto:触底自动加载
加载中...
total 剩余计数 + 自动收敛
加载中...
加载更多(loadMode 三态,默认 button)
| loadMode | 行为 | 场景 |
|---|---|---|
'button'(默认) | 底部按钮,传 total 时带计数「加载更多 (N)」:再传 pageSize 则 N = min(pageSize, 剩余),否则 N = 剩余 | 全列表页 |
'auto' | 近触底 IO 哨兵自动触发(autoThreshold 提前量;首屏未填满会持续填充) | 无限滚动列表 |
'none' | 纯网格 | 分类首页多行内容块;页码翻页(配 SwPagination,替换式整组换 items) |
追加式数据流:收到 @load-more 后往 items 追加;内部 busy 锁 + loading prop 双锁防重复触发(items 追加 / loading 收尾自动解锁,失败场景可重试)。无更多数据时置 finished(传了 total 时 remaining=0 自动视为到底)。
失败重试:请求失败时父层置 error: true,加载区变「加载失败,点击重试」按钮(点击照常 emit @load-more,父层重试发请求前清 error);auto 模式失败时哨兵移除、转手动重试(防失败自动循环),error 清掉并追加后自动恢复。
失败重试:error 置位 → 重试按钮 → 清错继续(含 page-size 按钮计数)
加载中...
loadMode none:分类首页内容块(纯网格)
加载中...
标准用法
<script setup lang="ts">
const items = ref<Movie[]>([])
const total = ref(0)
const loading = ref(false)
async function loadMore() {
loading.value = true
try {
const r = await request<MovieList>('/movie/list', { body: { offset: items.value.length } })
items.value = [...items.value, ...r.list]
total.value = +r.total
} finally {
loading.value = false
}
}
await loadMore()
</script>
<template>
<SwGallery :items="items" :total="total" :loading="loading" :min-item-width="180" @load-more="loadMore">
<template #default="{ item }">
<SwLink :to="`/movie/${item.id}`" :track="{ /* 卡片埋点走 SwLink,网格不内置 */ }">
<SwImage :src="item.img" :alt="item.name" ratio="2/3" />
<p>{{ item.name }}</p>
</SwLink>
</template>
</SwGallery>
</template>
Props
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
items | T[] | ✓ | — | 追加式数据源(泛型,组件不关心形状) |
minItemWidth | number | string | 240 | 卡片最小宽(auto-fill 模式)。number 视作 px;string 原样透传,可传 min(15.625rem, 46%) / var(--x) | |
columns | number | { mobile?, tablet?, desktop? } | undefined | 锁定列数,传了覆盖 minItemWidth | |
loadMode | 'button' | 'auto' | 'none' | 'button' | 加载更多模式 | |
loading | boolean | false | 外部加载态(双锁之一) | |
finished | boolean | false | 无更多数据 | |
total | number | undefined | 总数 → 按钮计数;remaining=0 视为到底 | |
pageSize | number | undefined | 每次加载条数 → 按钮计数显示 min(pageSize, 剩余);不传退回剩余数 | |
error | boolean | false | 上次加载失败(父层维护);true 时加载区变「加载失败,点击重试」 | |
autoThreshold | number | string | 200 | auto 哨兵提前量。number 视作 px;string 原样透传给 rootMargin,可用 % 按视口比例预取。运行时可改(会重建 IO) | |
ariaLabel | string | undefined | 传了才输出 role="region" + aria-label |
Events
| 名称 | 携带 | 说明 |
|---|---|---|
load-more | — | 请父层追加 items(双锁内防重复) |
Slots
| 名称 | 作用域 | 说明 |
|---|---|---|
default | { item, index } | 每张卡片(业务渲染全部视觉) |
load-more | { loading, remaining, error } | 自定义加载更多按钮区 |
finished | — | 到底文案(默认「已经到底了」) |
empty | — | items 为空的空态(默认「暂无内容」) |
Expose
| 名称 | 说明 |
|---|---|
loadMore() | 命令式触发一次加载(受双锁约束) |
CSS 变量
| 变量 | 默认 | 说明 |
|---|---|---|
--sw-gallery-gap | 1rem | 网格间距 |
--sw-gallery-min | 由 minItemWidth 写入 | 最小卡宽 |
--sw-gallery-template | 未设时走 minItemWidth 自适应 | 自定义断点逃生舱:columns prop 只有 mobile/tablet/desktop 三档,需要更多断点时不传 columns、改在自己的媒体查询里设本变量(值即 grid-template-columns)。与 columns 二选一,传了 prop 会覆盖它 |
注意事项
- 埋点不内置:卡片曝光 / 点击走卡片内 SwLink
:track;网格本身零上报。 - 翻页器场景:页码翻页是替换式数据流,用
loadMode="none"+ SwPagination 组合(framework#131),不要把页码塞进 Gallery。 - 选型对照(横滚 / 轮播 / 视频流 / 网格)见 SwRail 选型表。
- 失败重试要同时传
:loading:error/loading都由父层维护;失败时只传:error不传:loading,内部加载锁不释放、重试点击无效——请同时传:loading,并在重试发请求前把error清回false。 @load-more要配:finished或:total:两者都不传则永远判不到「到底」,button 模式按钮常驻、auto 模式哨兵反复触发拉空页(死循环)。无更多数据时置:finished="true",或传:total让剩余归零自动收敛。