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)」(即「載入更多 (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讓剩餘歸零自動收斂。