ListView 列表刷新
cl-list-view 组件结合 usePager() 钩子函数提供了完整的列表刷新解决方案,主要解决以下痛点:
- 避免使用 UTSJSONObject[] 类型定义列表数据,无法类型提示及不好维护
- 封装通用的下拉刷新和加载更多逻辑,减少重复代码
- 基于虚拟列表技术,实现大数据量场景下的高性能渲染
示例
查看以下 2 个文件,逐一分析为何这样使用
list.uvue
virtual属性用于控制是否启用虚拟列表渲染。启用时需要注意:- 必须设置固定的列表项高度
- 需要配置
bottomHeight以适配加载更多组件的显示 - 建议在大数据量场景下开启,小数据量场景可以关闭
pt.refresher提供下拉刷新区域的自定义样式能力refresher-enabled设置为true开启下拉刷新功能@pull下拉刷新事件,触发时会重置页码为 1,实现列表数据重新加载@bottom监听列表滚动到底部事件,用于触发加载更多数据#item建议将列表项封装为独立组件(如goods-item.uvue):- 避免直接使用
value["name"]的方式访问UTSJSONObject类型数据 - 提升代码可维护性和开发效率
- 方便复用和统一管理列表项样式
- 避免直接使用
#bottom用于自定义底部加载更多区域,通常配合cl-loadmore组件使用usePager分页钩子函数usePager(cb)的参数是一个方法,用于调用获取列表的接口tstype PagerCallback = (params: UTSJSONObject, ctx: Pager) => void | Promise<void>; type usePager(cb: PagerCallback): Pagerrefresh(params)刷新列表数据的方法params参数对象不能为空,可传入空对象{}- 通过
params可控制分页大小,如refresh({ size: 30 })设置每页显示 30 条
list列表数据,类型为UTSJSONObject[],可用于任意场景如v-for循环listView列表数据,类型为ClListViewItem[],专用于cl-list-view组件的data属性loading布尔值,表示是否正在加载数据loadmore()加载下一页数据的方法render()渲染列表数据,如下示例代码格式
onPull()下拉刷新事件处理函数- 在刷新完成后需调用
stopRefresh()停止刷新动画
- 在刷新完成后需调用
vue
<template>
<cl-page>
<cl-list-view
ref="listViewRef"
:data="listView"
:virtual="false"
:pt="{
refresher: {
className: 'pt-3',
},
}"
:refresher-enabled="true"
@pull="onPull"
@bottom="loadMore"
>
<template #item="{ value }">
<goods-item :value="value"></goods-item>
</template>
<template #bottom>
<view class="py-3">
<cl-loadmore :loading="loading" v-if="list.length > 0"></cl-loadmore>
</view>
</template>
</cl-list-view>
</cl-page>
</template>
<script lang="ts" setup>
import { useUi } from "@/uni_modules/cool-ui";
import { ref } from "vue";
import { usePager } from "@/cool";
import GoodsItem from "../components/goods-item.uvue";
import { t } from "@/locale";
const ui = useUi();
const listViewRef = ref<ClListViewComponentPublicInstance | null>(null);
let id = 0;
const { refresh, list, listView, loading, loadMore } = usePager(
(params, { render }) => {
// 模拟请求
setTimeout(() => {
render({
list: [
{
id: id++,
title: "春日樱花盛开时节,粉色花瓣如诗如画般飘洒",
image: "https://unix.cool-js.com/images/demo/1.jpg",
},
{
id: id++,
title:
"夕阳西下的海滩边,金色阳光温柔地洒在波光粼粼的海面上,构成令人心旷神怡的日落美景",
image: "https://unix.cool-js.com/images/demo/2.jpg",
},
{
id: id++,
title:
"寒冬腊月时分,洁白雪花纷纷扬扬地覆盖着整个世界,感受冬日的宁静与美好",
image: "https://unix.cool-js.com/images/demo/3.jpg",
},
],
pagination: {
page: params["page"],
size: params["size"],
total: 100,
},
});
ui.hideLoading();
}, 1000);
}
);
async function onPull() {
await refresh({ page: 1 });
listViewRef.value!.stopRefresh();
}
onReady(() => {
ui.showLoading(t("加载中"));
// 默认请求
refresh({});
});
</script>goods-item.uvue
- 根据业务需求定义商品类型
GoodsItem,包含必要的字段类型声明 - 使用
parse方法进行类型转换 - 在模板中使用可选链操作符
?.访问属性,避免空值引起的错误,如item?.image
vue
<template>
<view class="p-3 pb-0">
<view class="w-full p-3 bg-white rounded-xl dark:bg-surface-800">
<cl-image
:src="item?.image"
mode="aspectFill"
width="100%"
height="280rpx"
></cl-image>
<cl-text :pt="{ className: 'mt-2' }">{{ item?.title }}</cl-text>
</view>
</view>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { parse } from "@/cool";
defineOptions({
name: "goods-item",
});
type GoodsItem = {
id: number;
title: string;
image: string;
};
const props = defineProps({
value: {
type: Object,
default: () => ({}),
},
});
const item = computed(() => parse<GoodsItem>(props.value));
</script>


