微信小程序05---聊天室的搭建

二、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 时微信小程序各个接口的使用方法和参数!

猜你喜欢

转载自blog.csdn.net/Wr2138/article/details/127503550