关于开发即时聊天类功能的经验分享--Vue

当下即时通讯已经成为大多数产品的主要功能,最近在工作过程中需要初步开发一个具有基础通讯功能的客服功能。
根据此开发功能的过程,总结了一些开发经验与方法(使用的SDK不同,实现方法也会有比较大的差异)。
之前从来没有接触过这类功能的开发,不知道内部的功能是不是很复杂。
如果只是实现一个基础版的聊天功能,其实并不复杂,只需要把交互做好,功能基本就可以完成。
复制代码

前提准备

  • 成熟的即时通讯服务
  • 可调用的 SDK 与通俗易懂的文档
  • 可以提供答疑的人员

功能简介

  • 可实现文字、图片的发送与接收
  • 多人同时在线聊天
  • 记录聊天列表与历史记录,支持操作列表
  • 支持撤回、下载图片

核心功能

开发流程:SDK 方法登录 -> SDK 方法监听 -> Vuex 管理数据 -> 页面监听数据 -> 展示新消息

消息列表

前两步都是通讯服务提供的 SDK 方法,用于连接服务,建立会话,我们的主要内容在数据的处理与展示上。(如果准备工作不充分,开头两步可能会耗费很多时间~)

数据从监听处到我们的页面展示,数据都需要我们重新组装,因为他们服务的是很多项目,所以不可避免会有很多我们不需要的参数返回,同时还有一些我们自己需要使用的字段可以加进去。有了自己熟悉的数据结构,我们就可以根据结构来判断可以实现的功能。每当 SDK 监听消息的方法触发,数据经过重组存入 Vuex,页面的监听方法察觉到 Vuex 中的数据发生了改变,从而把修改好的数据加入到事先准备好的数组中,渲染到页面上,从而实现实时聊天的第一步,数据展示。但是光有数据展示是不够的,我们在微信使用过程中有几个必要的功能:

1. 下拉加载历史消息
2. 撤回消息
3. 下载图片
4. 聊天列表:消息提示、删除聊天等
5. 离线消息展示
复制代码

以上几条在这次的开发中都有实现,下面我一个个介绍:

下拉加载获取历史消息

对比微信我们不难发现,每次下拉,历史消息都会恰好的停留在顶部下来一条数据的距离,不会使得用户每次下拉消息还得找到刚刚看阅读的位置。

实现理念:通过获取下拉前与下拉后滚动元素的高度差,设置滚动条滚动的距离实现。

关键步骤

// 获取滚动元素的 DOM 
const dom = document.getElementById("scrollBox");
// 下拉之前的滚动条高度
const stepHeight = dom.scrollHeight;

// 下拉操作触发接口加载数据
// ...

// 获取加载后元素的滚动条高度
this.$nextTick(() => {
    const dom2 = document.getElementById("scrollBox");
    dom2.scrollTo(0, dom2.scrollHeight - stepHeight); // 滚动到之前高度的位置即可
})
复制代码

长按撤回

定义一个指令 longPress.js

在页面注册这个指令,然后在展示消息的标签上加入操作方法。

// 注意 因为消息我都单独写成了组件,所以我可以直接调用传入的数据,不需要通过函数入参传导
<div v-longPress="touchinBroker">{{ message.content }}</div>

touchinBroker() {
    // 处理数据撤回
    this.$emit("setMessage", this.message.id);
}
复制代码

下载图片

前提介绍:通讯服务返回的图片,需要通过 AJAX 中的 GET 方法来获取(需要传入一些参数),获取到的图片是 base64 格式的数据。

本来我打算直接用浏览器右键的下载图片功能,但是我发现下载的是一个 base64 文件,并不是图片,所以还是需要自己写一个下载功能,功能逻辑也比较简单,就是创建一个 canvas,然后把图片用 canvas 展示,再截图下载,代码如下:

export function downloadBase64Img(base64Data) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const MINE_TYPE = "image/png";
    const img = new Image();
    
    img.src = base64Data;
    img.onload = () => {
        canvas.height = img.height;
        canvas.width = img.width;
        ctx.drawImage(img, 0, 0, img.width, img.height);
        
        const imgUrl = canvas.toDataUrl(MINE_TYPE);
        const alink = document.createElement("a");
        
        alink.download = "img";
        alink.href = imgUrl;
        alink.dataset.downloadurl = [MINE_TYPE, alink.download, alink.href].join(":");
        
        document.body.appendChild(alink);
        alick.click();
        document.body.removeChild(alick);
    }
}
复制代码

聊天列表

由于我们使用的 IM 服务是我们公司自己研发的项目,很少项目在使用,所以提供的功能并不完善

聊天列表并不是和我最开始想的那么容易实现。

我当时想不就是一个列表,自己部门做了也没多麻烦。实际上开发过程中,凡是涉及到记录消息的地方都得同步更新列表,所以聊天的过程中有很多地方都需要调用接口去更新。而且我们需要与后端沟通如何设计这个列表的增删改查,耗费了很多时间在开发与测试上。如果SDK可以提供一个客服列表,那代码会简化非常多,页面也会去掉很多逻辑判断,这样就可以花更多的时间在实现辅助功能上,比如发送表情、转发消息等...

离线消息

每次登录后,监听方法都会检测是否有离线消息。利用这个方法,我们在页面设置一个只监听一次的方法,流程类似监听消息的流程。

总结

  1. 开发前做好功能预研。
  2. 利用好SDK提供的方法可以节约很多时间。
  3. 涉及到消息相关的方法,最好让提供服务的一方提供方法,自己去实现很容易事半功倍。
  4. 如果有关键的功能,服务提供的不符合需求,那么就需要慎重选择是否继续使用该服务,毕竟开发完成后,坑还是得自己填。
  5. 交互很重要,如果交互没做好,就等于页面充满bug,坑的也是自己。
  6. 设计人员提供的交互不一定能想的非常完美,可以多借鉴其他的聊天软件,这方面业界的标杆都很牛,可以提供很多思路,开发不应该只想着实现代码,还需要关注用户体验。

猜你喜欢

转载自juejin.im/post/7077889005945094152