之前学习 websocket 基本上都是后端,开几个黑窗口来模拟消息的收发。等到自己真正实战的时候,会发现无从下手,本文会将前后端串联起来,从实战出发,分为上下文,此篇先介绍下前端的 websocket 实现及思路。
前端使用的是 vue ,直接用 <script>
引入的方式。对于前端不是很熟悉的同学(不会一点都不会吧?),可以看下文章中的实现思路,了解下大致的实现思路便可。
前端 websocket
我们先看一个简单的 demo
- 简单 websocket 示例
//用于创建一个webSocket实例,执行后,客户端就会与服务端连接 var ws = new WebSocket("ws://localhost:8080/chat"); //用于指定连接成功后的回调函数 ws.onopen = function(evt) { console.log("Connection open ..."); //send方法用于向服务器发送数据 ws.send("Hello WebSockets!"); }; //用于指定收到服务器数据后的回调函数 ws.onmessage = function(evt) { console.log("Received Message: " + evt.data); ws.close(); }; //用于指定连接关闭后的回调函数 ws.onclose = function(evt) { console.log("Connection closed."); }; //用于指定报错时的回调函数 ws.onerror = function (evt) { console.log(evt.data) }; 复制代码
websocket的特点:
- 服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种
- 建立在 TCP 协议之上,服务器端的实现比较容易
- 可以发送文本,也可以发送二进制数据
- 没有同源限制,客户端可以与任意服务器通信
- 协议标识符是 ws(如果加密,则为wss),服务器网址就是 URL。如ws:localhost:8080/chat
浏览器,F12,可以查看数据收发详情:
实现思路
页面加载完成后,我们通过 new 一个webSocket实例,完成客户端就会与服务端连接,之后我们便可通过这个实例进行消息的收发。
消息的类型支持 文本、表情、图片、语音消息等。
对于文字类型,实现很简单,我们直接调取实例的 send("文本信息")
方法即可发送数据。其实对于其他类型的消息,最终也是转换为文本消息类型。
- 表情:其实就是服务器上保存的图片,发送表情的时候发送的是表情的标识(图片服务器上的地址),对方接受的时候就是通过此地址将表情渲染展示即可
- 图片:实现方式和表情类似,只不过需要把本地的图片先上传到服务器,然后再发送图片标识(图片服务器上的地址)
- 语音:实现方式和图片类似,需要在前端将语音录制然后上传到服务器,然后再发送语音标识(语音服务器上的地址)
- 视频:前端录制视频后上传发送标识;文件:上传本地不同类型的文件后发送文件标识。
消息模板
- 文字:
{userid:1,dstid:2,cate:1,media:1,content:"hello"}
- 图片:
{userid:1,dstid:2,cate:1,media:2,url:"http://www.wekenw.com/a/test.jpg"}
- 语音:
{userid:1,dstid:2,cate:1,media:3,url:"http://www.wekenw.com/a/test.mp3",anount:40}
释义:
- userid : 当前用户id(发送者)
- dstid : 目标用户id(接收者)
- cate : 单聊/群聊
- media : 消息类型
- content : 内容
- url : 资源地址
- anount : 音频时间长度
示例:
//{userid:2,dstid:3,cate:1,media:1,content:"hello"} var msg = { userid:1 dstid:2, cate:1, media:1, content:"hello" }; this.webSocket.send(JSON.stringify(msg)) 复制代码
页面展示
如上文,一条聊天记录是一个 msg 对象,那么展示聊天记录的时候,其实就是把包含 msg 的数组遍历出来,var msglist = [{userid:1,...},{userid:1,...},...]
伪代码:
<div v-for="item in msglist"> <!--如果是对方消息则显示头像(左边)--> <el-avatar v-if="!item.ismine"></el-avatar> <!--如果是文字消息,则展示--> <span v-if="item.msg.media==1" v-text="item.msg.content"></span> <!--如果是图片/表情消息,则展示--> <img v-if="item.msg.media==2" :src="item.msg.url"> <!--如果是语音消息,则展示--> <div v-if="item.msg.media==3"> <img class="audio" src="/asset/img/audiom.png"/> <audio id="audio4play" src="item.msg.url" style="display: none"></audio> </div> <!--如果是我发的消息,则显示头像(右边)--> <el-avatar v-if="item.ismine"></el-avatar> </div> 复制代码
页面组件使用的是 element ,官方地址 element.eleme.cn/#/zh-CN。
代码如下
<div class="chatmessBox" id="convo"> <el-row type="flex" :justify="item.ismine?'end':'star' " :class="item.ismine?'minemess':'' " v-for="item in msglist" :key="item.id"> <div class="flex" v-if="!item.ismine"> <el-avatar icon="el-icon-user-solid"></el-avatar> <div class="flex-col"><span class="name" v-text="item.account"></span></div> </div> <!--文字--> <div class="messBox" v-if="item.msg.media==1"> <span class="sjicon"></span> <span v-text="item.msg.content"></span> </div> <!--语音--> <div class="messBox" v-if="item.msg.media==3" @click="playaudio(item.msg.url)"> <img class="audio" src="/asset/img/audiom.png" style="width: 30px;margin: 0 0;"/> <span v-text="item.msg.amount+'″'"></span> </div> <!--表情--> <img v-if="item.msg.media==4" class="show-emoji" :src="item.msg.url"> <!--图片--> <el-image v-if="item.msg.media==5" class="show-img" style="width: 100px; height: 100px" :src="item.msg.url" :preview-src-list="[item.msg.url]"> </el-image> <div class="flex" v-if="item.ismine"> <el-avatar icon="el-icon-user-solid"></el-avatar> <div class="flex-col"><span class="name" v-text="item.account"></span></div> </div> </el-row> </div> 复制代码
源码
整套源码已上传到云仓库:
- github:github.com/wuchengshi/…
- gitee:gitee.com/wekenw/chat
部分截图