注册
web

⚡聊天框 - 微信加载历史数据的效果原来这样实现的

前言


我记得2021年的时候做过聊天功能,那时业务也只限微信小程序


那时候的心路历程是:



卧槽,让我写一个聊天功能这么高大上??


嗯?这么简单,不就画画页面来个轮询吗,加个websocket也还行吧


然后,卧槽?这查看历史聊天记录什么鬼,页面闪一下不太好啊,真的能做到微信的那种效果吗



然后一堆调研加测试,总算在小程序中查看历史记录没那么鬼畜了,但是总是感觉不是最佳解决方案。



那时打出的子弹,一直等到现在击中了我



最近又回想到了这个痛点,于是网上想看看有没有大佬发解决方案,结果还真被我找到了。


image.png


正文开始


1,效果展示


上才艺~~~


222.gif


2,聊天页面


2.1,查看历史聊天记录的坑


常规写法加载历史记录拼接到聊天主体的顶部后,滚动条会回到顶部、不在原聊天页面


直接上图


111.gif


而我们以往的解决方案也只是各种利用缓存scroll的滚动定位把回到顶部的滚动条重新拉回加载历史记录前的位置,好让我们可以继续在原聊天页面。


但即使我们做了很多优化,也会有安卓和苹果部分机型适配问题,还是不自然,可能会出现页面闪动


其实吧,解决方案只有两行css代码~~~


2.2,解决方案:flex神功


想优雅顺滑的在聊天框里查看历史记录,这两行css代码就是flex的这个翻转属性


dispaly:flex;
flex-direction: column-reverse

灵感来源~~~


333.gif


小伙伴可以看到,在加载更多数据时



滚动条位置没变、加载数据后还是原聊天页面的位置



这不就是我们之前的痛点吗~~~


所以,我们只需要翻转位置,用这个就可以优雅流畅的实现微信的加载历史记录啦


flex-direction: column-reverse


官方的意思:指定Flex容器中子元素的排列方向为列(从上到下),并且将其顺序反转(从底部到顶部)


如果感觉还是抽象,不好理解的话,那就直接上图,不加column-reverse的样子


image.png


加了column-reverse的样子


image.png


至此,我们用column-reverse再搭配data数据的位置处理就完美解决加载历史记录的历史性问题啦


代码放最后啦~~~


2.3,其他问题


2.3.1,数据过少时第一屏展示


因为用了翻转,数据少的时候会出现上图的问题


只需要.mainArea加上height:100%


然后额外写个适配盒子就行


flex-grow: 1; 
flex-shrink: 1;

image.png


2.3.2,用了scroll-view导致的问题


这一part是因为我用了uniappscroll-view组件导致的坑以及解决方案,小伙伴们没用这个组件的可忽略~~~


如下图,.mainArea使用了height:100%后,继承了父级高度后scroll-view滚动条消失了。


image.png


.mainArea去掉height:100%后scroll-view滚动条出现,但是第一屏数据过多时不会滚动到底部展示最新信息


image.png


解决方案:第一屏手动进行滚动条置顶


scrollBottom() {
if (this.firstLoad) return;
// 第一屏后不触发
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query
.select("#mainArea")
.boundingClientRect((data) => {
console.log(data);
if (data.height > +this.chatHeight) {
this.scrollTop = data.height; // 填写个较大的数
this.firstLoad = true;
}
})
.exec();
});
},

3,服务端


使用koa自己搭一个websocket服务端


3.1 服务端项目目录


image.png


package.json


{
"name": "websocketapi",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.14.2",
"koa-router": "^12.0.1",
"koa-websocket": "^7.0.0"
}
}


koa-tcp.js


const koa = require('koa')
const Router = require('koa-router')
const ws = require('koa-websocket')

const app = ws(new koa())
const router = new Router()

/**
* 服务端给客户端的聊天信息格式
* {
id: lastid,
showTime: 是否展示时间,
time: nowDate,
type: type,
userinfo: {
uid: this.myuid,
username: this.username,
face: this.avatar,
},
content: {
url:'',
text:'',
w:'',
h:''
},
}
消息数据队列的队头为最新消息,以次往下为老消息
客户端展示需要reverse(): 客户端聊天窗口最下面需要为最新消息,所以队列尾部为最新消息,以此往上为老消息
*/



router.all('/websocket/:id', async (ctx) => {
// const query = ctx.query
console.log(JSON.stringify(ctx.params))
ctx.websocket.send('我是小服,告诉你连接成功啦')
ctx.websocket.on('message', (res) => {
console.log(`服务端收到消息, ${res}`)
let data = JSON.parse(res)
if (data.type === 'chat') {
ctx.websocket.send(`我也会说${data.text}`)
}
})
ctx.websocket.on('close', () => {
console.log('服务端关闭')
})
})

// 将路由中间件添加到Koa应用中
app.ws.use(router.routes()).use(router.allowedMethods())

app.listen(9001, () => {
console.log('socket is connect')
})



切到server目录yarn


然后执行nodemon koa-tcp.js


没有nodemon的小伙伴要装一下


image.png


代码区


完整项目Github传送门


聊天页面的核心代码如下(包含data数据的位置处理和与服务端联动)



完结


这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。


到这里,想给小伙伴分享两句话



现在搞不清楚的事,不妨可以先慢下来,不要让自己钻到牛角尖了


一些你现在觉得解决不了的事,可能需要换个角度



欢迎转载,但请注明来源。


最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。


image.png


作者:尘落笔记
来源:juejin.cn/post/7337114587123335180

0 个评论

要回复文章请先登录注册