在上一篇文章中,我们介绍了alova从0到1的基本使用,今天我们继续使用alova来完成列表的加载与操作,希望能对你有所帮助。
1.分页加载
分页加载是一个非常常见的需求,特别是在一些后台管理系统中,表格+分页非常的常见。要完成这个需求,通常除了请求接口获取数据以外,我们还需要维护loading状态、处理分页数据、还需要支持关键词搜索筛选、防抖操作等,而这些,我们仅需要通过一个usePagination的hook就能完成。
import { getListWithTotal } from '@/API'
import { usePagination } from '@alova/scene-vue';
const { data: list, total, loading, page, pageSize } = usePagination((page, pageSize) => getListWithTotal(page, pageSize), {
append: false, // 数据不追加
data: res => res.list, // 定义如何取data数据
total: res => res.total, // 定义如何取total数据
initialPageSize: 20, // 设置默认pageSize
})
我们注意到,usePagination不仅帮我们维护好了列表数据,还有loading状态,当前页数page以及每一页数量pageSize,通过这些参数我们就可以配合一些分页组件,很方便的完成数据的分页加载。
要特别注意的是,对于page和pageSize,当其变化时,usePagination会自动发起接口请求,重新获取数据。
<n-data-table :columns="columns" striped :data="list" :max-height="350" :loading="loading" :pagination="false"/>
<n-pagination v-model:page="page" v-model:pageSize="pageSize" :item-count="total" :page-sizes="[10, 20, 30, 40, 50]" show-size-picker></n-pagination>
2.无限列表
无限列表是移动端场景的一个需求,用户滚到列表,快达到底部时,自动触发请求下一个的数据,其实其本质上也是一个分页加载。
除了需要维护loading状态以外,无限列表还需要额外对是否还有更多数据进行管理。
2.1 接口返回total
这种情况下,后台接口除了需要返回数据列表以外,还需要额外返回数据总量total,我们就可以根据total与当前前端的数据量进行对比,来判断是否还有更多数据。
/**
* 无限滚动,接口有total
*/
import { getListWithTotal } from '@/API'
import { usePagination } from '@alova/scene-vue';
import { throttle } from 'lodash-es'
// 后端接口有返回total数量的时候,isLastPage会按照total和当前list中的数量,大于等于时,则认为没有更多数据
const { data: list, loading, page, isLastPage, reload } = usePagination((page, pageSize) => getListWithTotal(page, pageSize), {
append: true, // 数据追加
data: res => res.list, // 定义如何取data数据
total: res => res.total, // 定义如何取total数据
initialPageSize: 20, // 设置默认pageSize
preloadNextPage: false,
preloadPreviousPage: false
})
const handleLoad = throttle(() => {
if (isLastPage.value) return
page.value++
}, 500)
注意这里,我们需要告诉usePagination如何去获取list数据,以及如何获取total的数量。
这样的话,我们就可以很方便的获取isLastPage的状态,而不需要去额外维护。
<section class="w-750px my-0 mx-auto">
<n-button @click="reload">刷新</n-button>
<n-infinite-scroll class="h-500px" :distance="50" @load="handleLoad">
<section v-for="p in list" :key="p.id" class="flex flex-row py-3 mb-4 border-b-(dashed gray)">
<img :src="p.photoUrls[0]" class="w-20 h-20 rounded-full mr-5" alt="">
<section class="flex flex-col h-20">
<h2 class="text-sm">{{ p.id }} - {{ p.name }}</h2>
<n-space>
<n-tag v-for="t in p.tags" :key="t.id" type="success" size="small">{{ t.name }}</n-tag>
</n-space>
</section>
</section>
<div v-if="loading" class="text-center">
加载中...
</div>
<div v-else-if="isLastPage" class="text-center">
没有更多了 🤪
</div>
</n-infinite-scroll>
</section>
有了list,loading,isLastPage,就可以很方便配合组件进行使用,快速完成一个加载更多列表的开发。
2.2 接口未返回total
后端没有返回total数量时,isLastPage 按照当前请求的返回的数据长度是否小于pageSize,如果pageSize=20,那么如果只返回10条数据,则默认认为没有更多数据了。
/**
* 无限滚动,接口有total
*/
import { getListNoTotal } from '@/API'
import { usePagination } from '@alova/scene-vue';
import { throttle } from 'lodash-es'
// 后端没有返回total数量时,isLastPage 按照当前请求的返回的数据长度是否小于pageSize,如果pageSize=20,那么如果只返回10条数据,则默认认为没有更多数据了
const { data: list, loading, page, isLastPage, reload } = usePagination((page) => getListNoTotal(page), {
append: true, // 数据追加
data: res => res, // 定义如何取data数据
preloadNextPage: false,
preloadPreviousPage: false
})
const handleLoad = throttle(() => {
if (isLastPage.value) return
page.value++
}, 500)
3.列表数据的插入、修改、删除
列表除了数据展示以外,我们通常还需要对列表进行一些额外的操作。
usePagination暴露出来的几个方法insert, replace, remove等可以帮助我们完成操作。
import { getListWithTotal, addPet } from '@/API'
import { usePagination } from '@alova/scene-vue';
import { throttle } from 'lodash-es'
const { data: list, loading, page, isLastPage, reload, insert, replace, remove } = usePagination((page, pageSize) => getListWithTotal(page, pageSize), {
append: true, // 数据追加
data: res => res.list, // 定义如何取data数据
total: res => res.total, // 定义如何取total数据
initialPageSize: 20, // 设置默认pageSize
preloadNextPage: false,
preloadPreviousPage: false
})
const handleLoad = throttle(() => {
if (isLastPage.value) return
page.value++
}, 500)
<section class="w-750px my-0 mx-auto">
<n-space>
<n-button @click="reload">刷新</n-button>
<n-button @click="mockAdd">插入数据</n-button>
</n-space>
<n-infinite-scroll class="h-500px" :distance="50" @load="handleLoad">
<section v-for="(p, idx) in list" :key="p.id" class="flex flex-row py-3 mb-4 border-b-(dashed gray)">
<img :src="p.photoUrls[0]" class="w-20 h-20 rounded-full" alt="">
<section class="flex flex-col h-20 mx-5">
<h2 class="text-sm">{{ p.id }} - {{ p.name }}</h2>
<n-space>
<n-tag v-for="t in p.tags" :key="t.id" type="success" size="small">{{ t.name }}</n-tag>
</n-space>
</section>
<section class="flex flex-col justify-center h-20">
<n-space>
<n-button @click="mockUpdate(idx)">修改</n-button>
<n-button @click="mockDel(idx)">删除</n-button>
</n-space>
</section>
</section>
<div v-if="loading" class="text-center">
加载中...
</div>
<div v-else-if="isLastPage" class="text-center">
没有更多了 🤪
</div>
</n-infinite-scroll>
</section>
3.1 插入数据
我们先请求接口(一般是发布接口),然后将数据插入到列表最前面。
// 模拟插入数据
const mockAdd = async () => {
const pet = await addPet().send()
insert(pet, 0)
}
3.2 修改数据
// 模拟修改
const mockUpdate = (idx: number) => {
const newPet = list.value[idx]
newPet.name = 'New Of ' + newPet.name
replace(newPet, idx)
}
通过replace方法,我们可以直接替换当前列表中指定位置的数据。
3.3 删除数据
通过remove方法,我们可以直接删除当前列表中指定位置的数据。
// 模拟删除
const mockDel = (idx: number) => {
remove(idx)
}
OK,以上就是usePagination的一些常用操作,希望对你有所帮助,减少你的代码量,提高你的代码质量。
另外本篇文章中所使用到的示例代码都已经上传到gitee仓库中,如有所需,欢迎自取。