引言
最近在做社交网站开发,过程中需要用到三种组件:通知列表组件、聊天列表组件和虚拟列表组件。这三种组件都是社交网站必备的,现在把我在开发中遇到的问题以及代码全部分享给大家,希望对大家有所帮助。
通知列表
我们在使用社交网站的过程中会发现他们通常会使用下拉通知展现通知列表数据,这种就是现在要介绍的通知列表,如图所示:
首先我们先来介绍下通知下拉列表的工作原理:
1、点击通知按钮
2、查询列表数据并展现
3、向下拉滚动条过程中分页加载数据,并把数据合并到列表中,直到数据全部加载完
现在看看我们如何制作吧。首先,我们需要使用一个React插件:InfiniteScroll,废话不多说直接上代码:
{
loading&&page.pageNum === 1? :}
scrollableTarget="scrollableDiv">
(your list item in here)}
/>
}
我们看一下上面的代码,首先我们要定义一个id=scrollableDiv
的div,接着判断如果当前页码是1的话,则显示loading加载组件。
注意: 因为
InfiniteScroll
组件,默认如果没有数据是不主动触发next
对应的loadMoreData
获取下一页数据的方法,所以最好我们打开下拉框的时候就主动去获取列表第一页的数据,在获取过程中我们可以先用loading
效果展示给用户,目的是为了提升更好的体验,当然你也可以不用加!
loading&&page.pageNum === 1?
现在,来看看这段代码:
}
scrollableTarget="scrollableDiv">
(your list item in here)}
/>
不知道大家有没有看InfiniteScroll
文档上面的代码,如果没有的话,我这里就简单介绍一下,并且把开发过程中遇到的问题给大家点明一下防止入坑。dataLength={remindList.length}
表示当前数据长度next={loadMoreData}
表示获取下一页数据的方法,它会随着滚动条的滚动自动触发的hasMore={remindList.length 表示什么时候显示
loading
效果loader={
表示loading
效果组件scrollableTarget
表示它是依赖于id=scrollableTarget
的div的
注意:1、这里需要注意的是
dataLength
应该是当前列表的长度,否则滚动条滚动到列表底部的时候不会触发获取下一页数据的方法loadMoreData
2、因为下拉列表滚动加载过程中,列表数据源remindList
是一直增加的,它是把每页的数据源merge在一起的。
私信列表
私信列表就比较特殊了,大家都用过微信,QQ的,它的聊天记录是向上滚动加载,跟我们的通知下拉列表刚好相反,庆幸的是InfiniteScroll
组件也提供该功能,直接上代码:
}
style={{
display: "flex",
flexDirection: "column-reverse"
}}
scrollableTarget="scrollableDiv"
inverse={true}>
your list item in here
跟之前一样,我们来分析下这段代码,因为是滚动条向上滚动加载,所以我们要把loading
放置在顶部,所以要加上inverse={true}
,同时还要设置两个样式:
样式一、
style={{
display: "flex",
flexDirection: "column-reverse"
}}
样式二、
.chatList{
height: calc(100vh - 186px);
overflow-y: auto;
display: flex;
flex-direction: column-reverse;
overflow-anchor: none;
}
这样就完成了反向上拉加载分页数据了,其它属性跟上面大同小异这里就不过多描述了,不过要注意几个问题:
注意:1、我在向上滚动的时候分页也成功了,也合并到列表中,可是滚动条一直在顶部,看过qq和微信的同学应该都知道,向上滚动加载的时候,滚动条应该在当前聊天记录上,而不是在最顶部,然后在网上搜索才知道,只要在父节点上加上这个代码就可以了:
overflow-anchor: none;
2、聊天记录的列表跟下拉通知列表数据也是相似的,每次向上滚动的时候我们都会合并到chatList(暂定为聊天记录列表名)中,但是有一点不一样,我可以通过输入聊天内容并展现到列表中,通知下拉可是没有输入展现功能,这点非常重要,因为我们会遇到一个非常棘手的问题:如何正确合并数据?以及合并数据之后分页查询重复问题?
正确合并数据:估计好多小伙伴已经想到了,后台把数据推送给前端之后,直接concat到chatList中(注意不是分页查询,因为那样页面会有闪动的不好体验),这也没问题
分页查询重复问题:我们来看看什么是分页查询重复问题,这里有篇文章大家可以看看,于是我们使用了上面第2种解决方案。
解决分页查询重复问题
解决思路2
请求第1页时记录第1条数据(即最新的那条)的写入时间, 然后后面查询第2,3,4…页数据, 把记录的写入时间作为参数, 然后在sql语句中做限制
例如查询第2页, 设置写入时间小于等于2019-05-15 19:31:59, 这样即使有新数据插入, 也不在我们本次分页查询的范围内.
select * from table1 where write_time既然我们已经知道了如何解决,下面给出具体步骤以及代码:
1、当后台推送数据给前端的时候,我们先把数据合并到chatList中,并给个标识
type=websocket
2、当用户向上滚动的时候,我们可以通过findIndex
拿到这个type=websocket
的数据的创建时间,通过分页接口传递给后台
3、后台返回数据之后我们再合并到chatList中分页代码:
export const getMessages = createAsyncThunk('notify/getMessages', async (params, thunkAPI) => { try { const notify = thunkAPI.getState().notify if (notify.chatListPage.pageNum > 1) { // 找到第1个type=websocket的数据,然后赋值给flagCreatedTime即可 // 为什么找到第1个?因为list中新加的websocket数据是从尾部开始加的,所以只要从索引0找到到最近一个type=websocket就是从这个时间开始算的,而不是最后一个 const i = notify.chatList.findIndex(item => item.type === 'websocket') if (i > -1) { params.flagCreatedTime = notify.chatList[i].createdDt } } const res = await axios.post(`/notify/crud/messages/getMessages`, { dialogId: params.dialogId, pageNum: params.pageNum, pageSize: params.pageSize, flagCreatedTime: params.flagCreatedTime }); return res.data } catch (error) { return thunkAPI.rejectWithValue({errorMsg: error.message}); } });
分页方法的回调:
[getMessages.fulfilled]:(state, action) => { if (action.payload.data) { // 获取总数 const total = action.payload.data.total state.chatListPage = { pageSize: action.payload.data.pageSize, pageNum: action.payload.data.pageNum, total: action.payload.data.total } const rows = action.payload.data.rows.reverse() // 这里做这个判断是因为react18 useeffect会执行两次,所以我根据Pagenum判断是否要合并以避免重复合并问题 if (action.payload.data.pageNum > 2) { state.chatList = [ ...rows, ...state.chatList ] } else { state.chatList = rows } // 设置是否要分页加载,InfiniteScroll组件的hasMore属性会用到 state.showChatListLoading = state.chatList.length
合并的代码:
// 接收消息并合并到chatList消息列表中 concatMessageInChatList: (state, action) => { if (action.payload.length > 0) { action.payload.forEach(item => { item.type = 'websocket'; }) } state.chatList = [ ...state.chatList, ...action.payload ] }
这样就能解决分页数据重复问题以及合并问题了。
虚拟列表
总结
引用
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net