介绍
放置在列表底部,做滚动加载使用,展示加载的各种状态。
代码演示
状态
通过设置 status 属性展示不同的状态信息;有四种状态:
INCOMPLETE: 未完成,处于此状态,会在触底或点击时触发load事件;LOADING: 加载中,处于此状态不会有任何交互;COMPLETE: 已完成,已经加载完所有数据,处于此状态不会有任何交互;ERROR: 加载错误,可以通过点击组件触发load事件来重试;
vue
<template>
<div>
<s-load-more disabled :status="status" @load="toast('加载数据')"></s-load-more>
<s-radio-group v-model="status" style="margin-top: 20px" #default="{ toggle }">
<s-list card>
<s-list-item
v-for="(item, i) in statusList"
:key="i"
:title="item"
hover
@click="toggle(item)"
#icon
>
<s-radio readonly :value="item" />
</s-list-item>
</s-list>
</s-radio-group>
</div>
</template>
<script setup lang="ts">
import { LoadMoreStatus, toast } from 'sard'
import { ref } from 'vue'
const status = ref(LoadMoreStatus.INCOMPLETE)
const statusList: LoadMoreStatus[] = [
LoadMoreStatus.INCOMPLETE,
LoadMoreStatus.LOADING,
LoadMoreStatus.COMPLETE,
LoadMoreStatus.ERROR,
]
</script>vue
<template>
<div>
<s-load-more disabled :status="status" @load="toast('加载数据')"></s-load-more>
<s-radio-group v-model="status" style="margin-top: 20px" #default="{ toggle }">
<s-list card>
<s-list-item
v-for="(item, i) in statusList"
:key="i"
:title="item"
hover
@click="toggle(item)"
#icon
>
<s-radio readonly :value="item" />
</s-list-item>
</s-list>
</s-radio-group>
</div>
</template>
<script setup lang="js">
import { LoadMoreStatus, toast } from 'sard'
import { ref } from 'vue'
const status = ref(LoadMoreStatus.INCOMPLETE)
const statusList = [
LoadMoreStatus.INCOMPLETE,
LoadMoreStatus.LOADING,
LoadMoreStatus.COMPLETE,
LoadMoreStatus.ERROR,
]
</script>基础使用
LoadMore 组件会获取最近一个滚动的祖先元素,当 LoadMore 出现在此祖先元素中时触发 load 事件,可在此事件回调中加载数据。
需要处理好加载状态和页码。
vue
<template>
<div
ref="scroll"
class="overflow-y-auto rounded-lg"
style="height: 300px; border: 1px solid var(--s-border-color)"
>
<s-list inlaid>
<s-list-item v-for="item in listData" :key="item.code" :title="item.name" />
</s-list>
<s-load-more :status="status" @load="getData" />
</div>
</template>
<script setup lang="ts">
import { LoadMoreStatus } from 'sard'
import { ref } from 'vue'
import { getProvinces } from '@/api'
const listData = ref<{ code: string; name: string }[]>([])
const status = ref<LoadMoreStatus>(LoadMoreStatus.INCOMPLETE)
let page = 1
const getData = async () => {
// 加载中
status.value = LoadMoreStatus.LOADING
return getProvinces({ page })
.then(({ list, total }) => {
listData.value = [...listData.value, ...list]
if (listData.value.length >= total || list.length === 0) {
// 已加载所有数据
status.value = LoadMoreStatus.COMPLETE
} else {
// 还可以继续加载数据
status.value = LoadMoreStatus.INCOMPLETE
// 再次请求会加载下一页数据
page++
}
})
.catch(() => {
// 加载失败
status.value = LoadMoreStatus.ERROR
})
}
</script>vue
<template>
<div
ref="scroll"
class="overflow-y-auto rounded-lg"
style="height: 300px; border: 1px solid var(--s-border-color)"
>
<s-list inlaid>
<s-list-item v-for="item in listData" :key="item.code" :title="item.name" />
</s-list>
<s-load-more :status="status" @load="getData" />
</div>
</template>
<script setup lang="js">
import { LoadMoreStatus } from 'sard'
import { ref } from 'vue'
import { getProvinces } from '@/api'
const listData = ref([])
const status = ref(LoadMoreStatus.INCOMPLETE)
let page = 1
const getData = async () => {
// 加载中
status.value = LoadMoreStatus.LOADING
return getProvinces({ page })
.then(({ list, total }) => {
listData.value = [...listData.value, ...list]
if (listData.value.length >= total || list.length === 0) {
// 已加载所有数据
status.value = LoadMoreStatus.COMPLETE
} else {
// 还可以继续加载数据
status.value = LoadMoreStatus.INCOMPLETE
// 再次请求会加载下一页数据
page++
}
})
.catch(() => {
// 加载失败
status.value = LoadMoreStatus.ERROR
})
}
</script>配合 PullDownRefresh 组件使用
下面的案例代码展示了经典的“下拉刷新+触底加载”。
在下拉刷新事件回调中重置页码;触底加载中需要禁用下拉刷新。
vue
<template>
<div
class="overflow-y-auto rounded-lg"
style="height: 300px; border: 1px solid var(--s-border-color)"
>
<s-pull-down-refresh
:loading="refreshing"
:disabled="status === LoadMoreStatus.LOADING"
@refresh="onRefresh"
>
<s-list inlaid>
<s-list-item v-for="item in listData" :key="item.code" :title="item.name" />
</s-list>
<s-load-more :status="status" @load="getData" />
</s-pull-down-refresh>
</div>
</template>
<script setup lang="ts">
import { toast, LoadMoreStatus } from 'sard'
import { ref } from 'vue'
import { getProvinces } from '@/api'
const listData = ref<{ code: string; name: string }[]>([])
// ============================ 加载更多 ============================
const status = ref<LoadMoreStatus>(LoadMoreStatus.INCOMPLETE)
let page = 1
const getData = async () => {
// 加载中
status.value = LoadMoreStatus.LOADING
return getProvinces({ page })
.then(({ list, total }) => {
listData.value = page === 1 ? list : [...listData.value, ...list]
if (listData.value.length >= total || list.length === 0) {
// 已加载所有数据
status.value = LoadMoreStatus.COMPLETE
} else {
// 还可以继续加载数据
status.value = LoadMoreStatus.INCOMPLETE
// 再次请求会加载下一页数据
page++
}
})
.catch(() => {
// 加载失败
status.value = LoadMoreStatus.ERROR
})
}
// ============================ 下拉刷新 ============================
const refreshing = ref(false)
const onRefresh = () => {
page = 1
refreshing.value = true
getData()
.then(() => {
toast('刷新成功')
})
.finally(() => {
refreshing.value = false
})
}
</script>vue
<template>
<div
class="overflow-y-auto rounded-lg"
style="height: 300px; border: 1px solid var(--s-border-color)"
>
<s-pull-down-refresh
:loading="refreshing"
:disabled="status === LoadMoreStatus.LOADING"
@refresh="onRefresh"
>
<s-list inlaid>
<s-list-item v-for="item in listData" :key="item.code" :title="item.name" />
</s-list>
<s-load-more :status="status" @load="getData" />
</s-pull-down-refresh>
</div>
</template>
<script setup lang="js">
import { toast, LoadMoreStatus } from 'sard'
import { ref } from 'vue'
import { getProvinces } from '@/api'
const listData = ref([])
// ============================ 加载更多 ============================
const status = ref(LoadMoreStatus.INCOMPLETE)
let page = 1
const getData = async () => {
// 加载中
status.value = LoadMoreStatus.LOADING
return getProvinces({ page })
.then(({ list, total }) => {
listData.value = page === 1 ? list : [...listData.value, ...list]
if (listData.value.length >= total || list.length === 0) {
// 已加载所有数据
status.value = LoadMoreStatus.COMPLETE
} else {
// 还可以继续加载数据
status.value = LoadMoreStatus.INCOMPLETE
// 再次请求会加载下一页数据
page++
}
})
.catch(() => {
// 加载失败
status.value = LoadMoreStatus.ERROR
})
}
// ============================ 下拉刷新 ============================
const refreshing = ref(false)
const onRefresh = () => {
page = 1
refreshing.value = true
getData()
.then(() => {
toast('刷新成功')
})
.finally(() => {
refreshing.value = false
})
}
</script>页面触底加载
当没有获取到滚动元素时,会以页面窗口作为相交容器。
vue
<template>
<doc-page gray title="页面触底加载">
<s-list>
<s-list-item v-for="item in listData" :key="item.code" :title="item.name" />
</s-list>
<s-load-more :status="status" @load="getData" />
</doc-page>
</template>
<script setup lang="ts">
import { LoadMoreStatus } from 'sard'
import { ref } from 'vue'
import { getCities } from '@/api'
const listData = ref<{ code: string; name: string }[]>([])
const status = ref<LoadMoreStatus>(LoadMoreStatus.INCOMPLETE)
let page = 1
const getData = async () => {
// 加载中
status.value = LoadMoreStatus.LOADING
return getCities({ page })
.then(({ list, total }) => {
listData.value = [...listData.value, ...list]
if (listData.value.length >= total || list.length === 0) {
// 已加载所有数据
status.value = LoadMoreStatus.COMPLETE
} else {
// 还可以继续加载数据
status.value = LoadMoreStatus.INCOMPLETE
// 再次请求会加载下一页数据
page++
}
})
.catch(() => {
// 加载失败
status.value = LoadMoreStatus.ERROR
})
}
</script>vue
<template>
<doc-page gray title="页面触底加载">
<s-list>
<s-list-item v-for="item in listData" :key="item.code" :title="item.name" />
</s-list>
<s-load-more :status="status" @load="getData" />
</doc-page>
</template>
<script setup lang="js">
import { LoadMoreStatus } from 'sard'
import { ref } from 'vue'
import { getCities } from '@/api'
const listData = ref([])
const status = ref(LoadMoreStatus.INCOMPLETE)
let page = 1
const getData = async () => {
// 加载中
status.value = LoadMoreStatus.LOADING
return getCities({ page })
.then(({ list, total }) => {
listData.value = [...listData.value, ...list]
if (listData.value.length >= total || list.length === 0) {
// 已加载所有数据
status.value = LoadMoreStatus.COMPLETE
} else {
// 还可以继续加载数据
status.value = LoadMoreStatus.INCOMPLETE
// 再次请求会加载下一页数据
page++
}
})
.catch(() => {
// 加载失败
status.value = LoadMoreStatus.ERROR
})
}
</script>API
LoadMoreProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| status | 加载的状态 | LoadMoreStatus | LoadMoreStatus.INCOMPLETE |
| incomplete-text | 未加载完的状态文本 | string | '加载更多' |
| loading-text | 加载中的状态文本 | string | '加载中...' |
| complete-text | 加载完的状态文本 | string | '没有更多了' |
| error-text | 加载错误的状态文本 | string | '请求失败,点击重新加载' |
| root-margin | 用于 IntersectionObserver 的 rootMargin 配置,控制触底加载的提前量 | string | - |
| disabled | 禁用触底加载,仅用于演示 | boolean | false |
| invisible | 隐藏组件,不占地方,但仍然能观察是否相交 | boolean | false |
LoadMoreSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| incomplete | 自定义未加载完的状态内容,会覆盖 incompleteText 属性 | - |
| loading | 自定义加载中的状态内容,会覆盖 loadingText 属性 | - |
| complete | 自定义加载完的状态内容,会覆盖 completeText 属性 | - |
| error | 自定义加载错误的状态内容,会覆盖 errorText 属性 | - |
LoadMoreEmits
| 事件 | 描述 | 类型 |
|---|---|---|
| load | 在触底或在 INCOMPLETE | ERROR 状态下点击时触发 | () => void |
LoadMoreStatus
ts
enum LoadMoreStatus {
INCOMPLETE = 'incomplete', // 未完成
LOADING = 'loading', // 加载中
COMPLETE = 'complete', // 已完成
ERROR = 'error', // 加载错误
}主题定制
样式变量
| CSS 变量 | 值 |
|---|---|
--s-load-more-height | var(--s-size-4xl) |
--s-load-more-font-size | var(--s-font-size-sm) |
--s-load-more-color | var(--s-text-color-tertiary) |