本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
当我们在页面展示列表的时候,数据过多时,接口通常会弄分页,前端需要传入不同的页数(page) 和 一页多少条数据(pageSize) 来掉取数据,然后依次展示即可~
条件
当你需要 一个分页的接口,展示列表的数据,需要懒加载,但不想麻烦处理接口,处理数据、处理样式的时候。 可以尝试用用这个组件
大体思路
在这里我们需要使用 ant-mobile的 infiniteScroll这个组件,我们在此基础上结合接口封装,达到列表懒加载
先说说没有这个组件时候,我通常是如何处理的:在用户拉动列表到底部的时候,监听滚动条的高度,当可视区域的高度 + 滚动条滚动的高度 > 滚动内容高度 的时候做判断就OK了
const onScroll = () => {
let clientHeight = scrollRef.current.clientHeight; //可视区域高度
let scrollTop = scrollRef.current.scrollTop; //滚动条滚动高度
let scrollHeight = scrollRef.current.scrollHeight; //滚动内容高度
if((clientHeight+scrollTop + 100) >(scrollHeight) && curPage <= allNumber){
......
}
}
<div onScroll={onScroll} ref={scrollRef}>
这里最好多加入点像素,以防有些时候触发不了,题外话~~~
怎样将 infiniteScroll 与 接口结合起来,形成 ScrollList 组件
首先关于 infiniteScroll 的 Api 非常简单,只有简单的三个属性
- loadMore: 加载更多的回调函数
- hasMore :是否还有更多内容
- threshold: 触发加载事件的滚动触底距离阈值,单位为像素
我可以看到,最主要的就是 loadMore 这个参数,他是这个组建的核心,所以需要围绕这个属性去修改
我们通过传参来选择接口返回的数据,然后将数据累加,并判断数据的合 是否等于总数据,然后将数据返回出去,这是返回的data就可循环做一写操作,通过 childrenNode返回节点就ok了
同时也可以通过 LoadingNode来控制 加载时的样式 NoneNode来控制加载完成时的样式
代码案例
使用方法
import { useState, useEffect } from 'react';
import { ScrollList } from '@/components';
import { List } from 'antd-mobile'
import { Title } from '@/pages/commonPage'
import { getScrollList } from './services'
const Index = () => {
useEffect(() => {
}, [])
return (
<div style={{ padding: '6px 12px'}}>
<ScrollList
onRequest={getScrollList}
payload={{
sizeName: 'size',
sizeNumber: 20
}}
childrenNode={(data:any) => {
return <>
<div style={{ padding: 12 }}>展示数量/总数量:{data.list.length}/{data.res.all}</div>
<List>
{
data.list.map((item:any, index:any) => (
<List.Item key={index}>{item.name}</List.Item>
))
}
</List>
</>
}}
>
</ScrollList>
</div>
)
}
export default Index;
详细代码
import React, { useState } from 'react';
import { InfiniteScroll, Loading } from 'antd-mobile'
import { IndexProps } from './interface.d'
import { useReactive } from 'ahooks';
/**
* @module 无限滚动,列表懒加载
*/
function setWait(number:number) {
return new Promise((resolve:any) => {
setTimeout(() => {
resolve();
}, number);
});
}
const Index:React.FC<IndexProps> = ({ onRequest, payload, calcData, childrenNode, LoadingNode, NoneNode, threshold = 250, wait = 1000}) => {
let [node, setNode] = useState<React.ReactNode>(<></>)
const state = useReactive<any>({
hasMore: true,
page: 1,
number: 0,
data: []
})
const loadMore = async () => {
await setWait(wait)
let params:any = {}
params[payload?.pageName || 'page'] = state.page;
params[payload?.sizeName || 'pageSize'] = payload?.sizeNumber || 10;
const res = await onRequest(calcData ? { ...calcData(), ...payload} : params)
const number = state.number + res[payload?.list || 'list'].length;
const data = [...state.data, ...res[payload?.list || 'list']]
delete res[payload?.list || 'list']
setNode(childrenNode({ list: data, res }))
state.hasMore = false
state.number = number
state.data = data
if(res[payload?.all || 'all'] <= number){
state.hasMore = false
}else{
state.hasMore = true
state.page++
}
}
const InfiniteScrollContent = ({ hasMore }: { hasMore?: boolean }) => {
return (
<>
{hasMore ? LoadingNode ? (<>{LoadingNode}</>) : (
<>
<span>加载中</span>
<Loading />
</>
) : NoneNode ? (<>{NoneNode}</>) : (
<span>--- 我是有底线的 ---</span>
)}
</>
)
}
return (
<>
{node}
<InfiniteScroll loadMore={loadMore} hasMore={state.hasMore} threshold={threshold}>
<InfiniteScrollContent hasMore={state.hasMore} />
</InfiniteScroll>
</>
);
}
export default Index;
export interface IndexProps {
onRequest:any; //请求接口
payload?: PayloadProps; //请求参数,需要将页数,第几页分开写
calcData?: () => {}; // 其余参数
childrenNode: (data:any) => React.ReactNode; //列表渲染的节点,data 包含两个字段,list 为每次返回列表的总和,使用这个数据渲染,res为每次请求后除list的字段
LoadingNode?: React.ReactNode; //加载时的样式
NoneNode?: React.ReactNode; // 加载完成时的样式
threshold?: number; //触发加载事件的滚动触底距离阈值 单位为像素 默认 250
wait?: number; //等待时间,如果接口速度较慢时,可设置为0, 默认为 1000 ms
}
interface PayloadProps{
pageName?: string; // 接口页数的字段,默认 page
sizeName?: string; // 一页数量的名字,默认为 pageSize
sizeNumber?: number; // 一页数量,默认为 10
all?: string; //接口返回总数的字段 默认 all
list?: string; //接口返回总数的列表的字段 默认为 list
}
致谢
- 感兴趣的小伙伴可观看在线地址 react-mobile-Domesy
- 如果觉得写的不错,请务必给个 Star 支持下~~ gitHub地址:react-mobile