原文:https://juejin.cn/post/7337114587123335180?searchId=20240509192958AF7D129567F92AD7E083
公众号:程序员白特,欢迎一起交流学习~
前言
我记得2021年的时候做过聊天功能,那时业务也只限微信小程序
那时候的心路历程是:
❝
卧槽,让我写一个聊天功能这么高大上??
嗯?这么简单,不就画画页面来个轮询吗,加个websocket也还行吧
然后,卧槽?这查看历史聊天记录什么鬼,页面闪一下不太好啊,真的能做到微信的那种效果吗
❞
然后一堆调研加测试,总算在小程序中查看历史记录没那么鬼畜了,但是总是感觉不是最佳解决方案。
❝
那时打出的子弹,一直等到现在击中了我
❞
最近又回想到了这个痛点,于是网上想看看有没有大佬发解决方案,结果还真被我找到了。
正文开始
1,效果展示
上才艺~~~
2,聊天页面
2.1,查看历史聊天记录的坑
常规写法加载历史记录拼接到聊天主体的顶部后,滚动条会回到顶部、不在原聊天页面
直接上图
而我们以往的解决方案也只是各种利用缓存
、scroll的滚动定位
把回到顶部的滚动条重新拉回加载历史记录前的位置,好让我们可以继续在原聊天页面。
但即使我们做了很多优化,也会有安卓和苹果部分机型适配问题,还是不自然,可能会出现页面闪动
。
其实吧,解决方案只有两行css代码
\~~~
2.2,解决方案:flex神功
想优雅顺滑的在聊天框里查看历史记录,这两行css代码
就是flex的这个翻转属性
dispaly:flex;
flex-direction: column-reverse
「灵感来源~~~」
小伙伴可以看到,在加载更多数据时
❝
滚动条位置没变、加载数据后还是原聊天页面的位置
❞
这不就是我们之前的痛点吗~~~
所以,我们只需要翻转位置,用这个就可以优雅流畅的实现微信的加载历史记录啦
flex-direction: column-reverse
官方的意思:指定Flex容器中子元素的排列方向为列(从上到下),并且将其顺序反转(从底部到顶部)
如果感觉还是抽象,不好理解的话,那就直接上图,不加column-reverse
的样子
加了column-reverse
的样子
至此,我们用column-reverse
再搭配data数据的位置处理
就完美解决加载历史记录的历史性问题啦
代码放最后啦~~~
2.3,其他问题
2.3.1,数据过少时第一屏展示
因为用了翻转,数据少的时候会出现上图的问题
只需要.mainArea
加上height:100%
然后额外写个适配盒子就行
flex-grow: 1;
flex-shrink: 1;
2.3.2,用了scroll-view导致的问题
这一part是因为我用了uniapp
里 scroll-view
组件导致的坑以及解决方案,小伙伴们没用这个组件的**「可忽略~~~」**
如下图,.mainArea
使用了height:100%
后,继承了父级高度后scroll-view滚动条消失了。
.mainArea
去掉height:100%
后scroll-view滚动条出现,但是第一屏数据过多时不会滚动到底部展示最新信息
解决方案:第一屏手动进行滚动条置顶
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 服务端项目目录
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
的小伙伴要装一下
「代码区」
完整项目Github传送门
聊天页面的核心代码如下(包含data数据的位置处理和与服务端联动)
https://code.juejin.cn/pen/7337211042621521959(跳转链接或者点击下方阅读原文查看)