二、websocket的使用---聊天室
1、界面效果如下
2、链接聊天室
wss://showme.myhope365.com/websocketChat?username=&password=&courseId=&nickName=&avatar=
参数名 |
说明 |
示例 |
username |
用户名 |
可以使用用户loginname |
password |
密码 |
随便设置,这个后台开放连接 |
courseId |
分组id |
小组id |
nickName |
昵称 |
用户昵称 |
avatar |
头像 |
用户头像,需要编码和解码 |
3、发送消息的格式
所有发送的内容都是字符串,在发送的时候需要把对象转成字符串
-
发送聊天信息
{
from: "zhangsan", // 发送人,当前用户的用户名
createTime: new Date().getTime(), // 发送时间
cmd: 11, // 命令固定内容
group_id: '', // 分组id。 想要发送到哪个组里
chatType: 1, // 聊天类型 固定内容
msgType: 0, // 消息类型 固定内容
content: "", // 消息内容,自己设计结构,比如你想发送图片(图片上传的接口)
nickName: "张三", // 用户昵称
avatar: "", // 用户头像
type:"1" // 消息类型。 你可以自己设计,发送过去是什么,返回的就是什么(1: 普通文本 2: 图片 3:点赞 4, 送花)
}
-
获取历史记录
{
cmd: 19, // 命令
type: 1, // 类型 固定值
groupId: '', // 分组的id
userId: '' // 用户id(这里可以用loginName)
}
-
获取聊天室的人数
{
cmd: 17, // 命令
type: 0, // 类型
userid: '' // 用户id(可以用loginName)
}
-
心跳检测
{
"cmd":13, // 固定参数
"hbbyte":"-127" // 固定参数
}
4、 回执消息
command == 11
接收到聊天信息
command === 18
获取用户信息响应处理;
command === 12 && code === 10000
发送消息成功
command === 9
加入群组的消息通知处理
command === 10
退出群组的消息通知处理;
command === 20 && code === 10015
获取消息失败,未开启持久化处理 聊天室...
处理离线消息; (离线消息提示 )
command === 20 && code === 10016
处理离线消息; (暂时不用处理)
command === 20 && code === 10018
处理历史消息
5、核心代码
WXML
<view class="bgc"></view>
<view wx:if="{
{loadingSocket}}">
聊天室连接中...
</view>
<scroll-view class="chat-container" scroll-y scroll-into-view="{
{'k'+list[list.length-1].id}}">
<view class="chat-item {
{userName == item.from ? 'my-msg' : ''}}" wx:for="{
{list}}" id="{
{'k'+item.id}}">
<view class="avatar">
<image src="{
{item.avatar}}">
</image>
</view>
<view class="msg-box">
<view class="nickname" wx:if="{
{userName !== item.from}}">
{
{item.nickName}}
</view>
<view wx:if="{
{item.type == 1}}" class="content-box">
{
{item.content}}
</view>
<view wx:elif="{
{item.type==2}}" class="img-content" >
<image src="{
{item.content}}" mode="widthFix">
</image>
</view>
</view>
</view>
</scroll-view>
<view class="send-msg-container">
<input class="input" type="text" model:value="{
{value}}" />
<view class="action-box">
<van-icon name="smile-o" class="icon" bind:tap="sendImg" />
<van-button class="send-btn" square type="primary" bind:tap="sendMsg">发送</van-button>
</view>
</view>
WXSS
/* pages/chat/index.wxss */
.bgc {
background-color: #E1E0E5;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
/* *****************消息区域***************** */
.chat-container {
padding-bottom: 110rpx;
height: 100vh;
box-sizing: border-box;
}
.chat-item{
display: flex;
padding: 20rpx 0;
}
.avatar{
width: 120rpx;
flex-shrink: 0;
display: flex;
justify-content: center;
}
.avatar image {
width: 90rpx;
height: 90rpx;
border-radius: 10rpx;
}
.msg-box{
padding: 0 10rpx;
}
.content-box{
background-color: #fff;
padding: 15rpx 20rpx;
border-radius: 5rpx;
margin-top: 10rpx;
position: relative;
max-width: 400rpx;
}
.content-box::before {
content: " ";
background-color: white;
height: 25rpx;
width: 25rpx;
position: absolute;
left: -8rpx;
top: 22rpx;
transform: rotate(45deg);
}
.img-content image {
max-width: 400rpx;
border-radius: 10rpx;
}
/* *****************消息区域***************** */
/* *****************发送消息区域***************** */
.send-msg-container {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
display: flex;
background-color: #F7F7F7;
/* background-color: hotpink; */
height: 110rpx;
align-items: center;
box-sizing: border-box;
padding: 0 10rpx;
}
.input {
background-color: #FFFFFF;
flex-grow: 1;
margin: 0 10rpx;
height: 68rpx;
border-radius: 10rpx;
padding: 0 15rpx;
box-sizing: border-box;
}
.action-box{
display: flex;
width: 200rpx;
flex-shrink: 0;
}
.action-box .icon {
font-size: 55rpx;
color: #282828;
}
.action-box .send-btn .van-button {
height: 60rpx;
margin-left: 14rpx;
}
/* *****************发送消息区域***************** */
/* *****************我发送的消息***************** */
.my-msg {
flex-direction: row-reverse;
}
.my-msg .content-box::before {
left: auto;
right: -8rpx;
}
/* *****************我发送的消息***************** */
JS
export function uploadFile(url, name = "file", formData = {}, options = {}) {
return new Promise((reslove, reject) => {
// 图片上传发送
wx.chooseImage({
success: res => {
const tempFilePaths = res.tempFilePaths
wx.uploadFile({
//仅为示例,非真实的接口地址
url,
filePath: tempFilePaths[0],
// 上传文件对应的key值,这个值在接口文档里找
name,
// 除了文件之外额外的参数
formData,
header: {
"cookie": wx.getStorageSync("cookie") || ""
},
...options,
success: res => {
// 请求成功的回调
const data = JSON.parse(res.data)
reslove(data)
}
})
}
})
})
}
import {
uploadFile
} from "../../utils/request"
const app = getApp()
// pages/chat/index.js
Page({
/**
* 页面的初始数据
*/
data: {
loadingSocket: true,
value: "",
list: [],
userName: ""
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
if (app.globalData.isLogin) {
const userInfo = app.globalData.user
// 准备数据
this.userName = userInfo.loginName;
this.setData({
userName: this.userName
})
// 随便输入
// courseId 分组id 通过这个courseId来标识不同的聊天室
this.groupId = "web20" + options.id
// nickName 昵称
this.nickName = userInfo.userName
// 头像
this.avatar = userInfo.avatar
// 登录
this.connectSocket();
// 监听链接打开
this.onSocketOpen()
// 接受服务器消息
this.onSocketMessage()
} else {
// 未登录
wx.reLaunch({
url: '/pages/login/index',
})
}
},
connectSocket() {
const url = `ws://showme2.myhope365.com/websocketChat?username=${this.userName}&password=123&courseId=${this.groupId}&nickName=${this.nickName}&avatar=${this.avatar}`
// 建立链接
wx.connectSocket({
// 要链接的socket服务器的地址
url,
})
},
onSocketOpen() {
// 监听链接建立成功
wx.onSocketOpen((result) => {
// 当我们socket链接打开之后执行
// 需要保证的时候,我们在发送消息之前一定要先链接成功
console.debug("socket链接已经打开了");
this.setData({
loadingSocket: false
})
// 链接打开之后加载历史消息
this.getHistory()
// 添加心跳检测
this.intervalId = setInterval(() => {
wx.sendSocketMessage({
data: JSON.stringify({
"cmd":13, // 固定参数
"hbbyte":"-127" // 固定参数
}),
})
}, 5000);
})
},
onSocketMessage() {
// 接受服务端的消息
wx.onSocketMessage((result) => {
const data = JSON.parse(result.data)
console.debug(data);
// 针对不同类型的消息进行一些处理
if (data.command === 11) {
// 有新消息
this.data.list.push(data.data)
this.setData({
list: this.data.list
})
} else if (data.command === 20 && data.code === 10018) {
// 服务端返回了历史消息
if(data.data){
this.setData({
list: data.data.groups[this.groupId]
})
}
}
})
},
getHistory() {
const historyBody = {
cmd: 19, // 命令
type: 1, // 类型 固定值
groupId: this.groupId, // 分组的id
userId: this.userName // 用户id(这里可以用loginName)
}
wx.sendSocketMessage({
data: JSON.stringify(historyBody),
})
},
sendSocketMsg(content, type) {
const msgBody = {
from: this.userName, // 发送人,当前用户的用户名
createTime: new Date().getTime(), // 发送时间
cmd: 11, // 命令固定内容
group_id: this.groupId, // 分组id。 想要发送到哪个组里
chatType: 1, // 聊天类型 固定内容
msgType: 0, // 消息类型 固定内容
content, // 消息内容,自己设计结构,比如你想发送图片(图片上传的接口)
nickName: this.nickName, // 用户昵称
avatar: this.avatar, // 用户头像
type // 消息类型。 你可以自己设计,发送过去是什么,返回的就是什么(1: 普通文本 2: 图片 3:点赞 4, 送花)
}
wx.sendSocketMessage({
data: JSON.stringify(msgBody),
})
},
sendMsg() {
if (!this.data.value) {
wx.showToast({
title: '请输入消息内容',
icon: "none"
})
return
}
this.sendSocketMsg(this.data.value, "1")
this.setData({
value: ""
})
},
sendImg() {
// 图片上传发送
uploadFile('https://showme.myhope365.com/api/nos/upload/image', "file", {
'fileUseForEnum': 'DEFAULT'
}).then(res => {
this.sendSocketMsg(res.url, "2")
})
},
onUnload(){
// 进行卸载操作
wx.closeSocket({
code: 1000,
})
// 清除计时器
clearInterval(this.intervalId)
}
})
总的书写顺序(和上方代码略有出入,但大体不变)
登陆连接
打开监听连接 + 请求历史数据 + 心跳检测
接收服务器信息
JSON
{
"usingComponents": {
"van-icon": "@vant/weapp/icon/index",
"van-button": "@vant/weapp/button/index"
}
}
注意在使用 webSocket 时微信小程序各个接口的使用方法和参数!