express如何使用websocket进行实时通讯

效果图:

1、首先安装依赖

javascript 复制代码
npm install express
npm install express-ws

2、在index.js中引用

javascript 复制代码
import express from "express";
import expressWs from "express-ws";

这边我是用的es6模块化导入语法,可以在package.json中设置"type": "module"

3、使用expressWs

javascript 复制代码
const app = express()
expressWs(app);
// 每个在线用户所发送的消息
const wss = expressWs(app).getWss('/')

4、发起请求

javascript 复制代码
app.ws('/socket', (ws, req) => {
  console.log('连接成功');
  try {
    // 监听消息事件
    ws.on('message', msg => {
      console.log('serve message', msg);
      let msgObj = JSON.parse(msg)
      let sql = 'insert into chat_messages set ?'
      wss.clients.forEach((e) => {
        msgObj.date = moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
        e.send(JSON.stringify(msgObj))
      })
      db.query(sql, JSON.parse(msg), (err, data) => {
        if (err) return ws.send('sql出错了' + err.message);
        if (data.affectedRows !== 1) return res.send({
          code: 2,
          message: '用户信息保存数据库失败'
        })
      })
    })
    ws.on('open', () => {
      console.log('serve open');
    })
    ws.on('error', () => {
      console.log('serve error');
    })
    ws.on('close', () => {
      console.log('serve close');
    })
  } catch (error) {
    console.log(error);
  }
});
app.listen(3000, () => {
  console.log('运行于http://127.0.0.1:3000');
})

不存数据库的话这部可以不要

javascript 复制代码
db.query(sql, JSON.parse(msg), (err, data) => {
   if (err) return ws.send('sql出错了' + err.message);
   if (data.affectedRows !== 1) return res.send({
     code: 2,
     message: '用户信息保存数据库失败'
   })
 })

5、前端vue代码

javascript 复制代码
<template>
  <div>
    <div ref="messagesContainer" :style="{ width: '450px',height: contentHeight + 'px',border: '1px solid #ccc', marginBottom: '16px',overflow: 'auto',padding: '10px' }">
      <!-- <p style="text-align: center;font-size: 14px">您正在和{{ username }}聊天</p> -->
      <div style="width: 100%" v-for="(item, index) in messageList" :key="index">
        <div style="width: 300px;margin-bottom: 10px;" :class="item.userid === userid ? 'right' : ''">
          <h3 style="font-size: 14px;margin-bottom: 5px;" :class="item.userid === userid ? 'title_right' : ''">{{ item.username }} {{ moment(item.create_time).format('YYYY-MM-DD HH:mm:ss') }}</h3>
          <div style="width: 100%;">
            <div :class="item.userid === userid ? 'float_left' : 'float_right'" style="width: 250px;min-height: 40px;background-color: #e8e8e9;padding: 10px;white-space: wrap;border-radius: 10px;">{{ item.message }}</div>
            <div :class="item.userid === userid ? 'float_left' : 'float_right'" style="width: 40px;height: 40px;">
              <img :src="item.imgUrl" alt="" style="width: 100%;height: 100%;object-fit: cover;">
            </div>
            <div style="clear: both;"></div>
          </div>
        </div>
        <div style="clear: both;"></div>
      </div>
    </div>
    <Input v-model="message" placeholder="请输入内容" style="width: 280px" @on-enter="sendMessage"/>
    <Button type="success" @click="sendMessage" style="margin: 10px;">发送</Button>
    <Button type="success" @click="clear">清空记录</Button>
  </div>
</template>
<script setup>
import moment from 'moment';
import { onMounted, reactive, ref, nextTick, onUpdated } from 'vue';
import { Message } from 'view-ui-plus'
import { getMessageListApi } from '../../utils/message.js'
let message = ref('')
let messageList = reactive([])
let messagesContainer = ref(null)
let socket = new WebSocket('http://127.0.0.1:3000/socket')
let username = JSON.parse(localStorage.getItem('userinfo')).nickname
let imgUrl = JSON.parse(localStorage.getItem('userinfo')).imgUrl
let userid = JSON.parse(localStorage.getItem('userinfo')).id
let contentHeight = ref(document.documentElement.clientHeight - 240)
onMounted(() => {
  initSocket()
  nextTick(() => {
    // 滚动到messagesContainer的底部
    scrollToBottom();
  });
  getMessageListApi().then(res => {
    try {
      if(res.code === 0) {
        messageList.push(...res.data)
      } else {
        Message.error(res);
      }
    } catch (error) {
      console.log(error);
    }
  })
})
onUpdated(() => {
  nextTick(() => {
    // 滚动到messagesContainer的底部
    setTimeout(scrollToBottom, 20)
  });
})
const initSocket = () => {
  console.log(socket);
  // 接收到消息的回调
  socket.onmessage = messageHandler
  // 连接成功后的回调
  socket.onopen = openHandler
  // 连接发生错误的回调
  socket.onerror = errorHandler
  // 关闭的回调
  socket.onclose = closeHandler
}
const messageHandler = (e) => {
    let msg = JSON.parse(e.data)
    console.log(msg);
    messageList.push(msg)
  }
const openHandler = () => {
  console.log('open');
}
const errorHandler = () => {
  console.log('发生了错误,重连中...');
}
const closeHandler = function(event) {
  console.log('WebSocket connection closed with code: ' + event.code + ' and reason: ' + event.reason);
  setTimeout(initSocket, 1500)
}
const sendMessage = () => {
  if (!message.value) {
    return Message.warning('输入的内容不能为空')
  }
  let obj = {
    userid,
    username,
    imgUrl,
    message: message.value
  }
  socket.send(JSON.stringify(obj))
  message.value = ''
  nextTick(() => {
    // 滚动到messagesContainer的底部
    setTimeout(scrollToBottom, 20)
  });
}

const clear = () => {
  console.log('清空');
}
const scrollToBottom = () => {
  messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight + 999;
}
</script>
<style lang="less" scoped>
.right {
  // margin-left: 125px;
  float: right;
}
.title_right {
  text-align: right;
}
.float_left {
  float: left;
  margin-right: 5px;
}
  .float_right {
  float: right;
  margin-left: 5px;
}
</style>
相关推荐
老码沉思录40 分钟前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁44 分钟前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
Dread_lxy6 小时前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
奔跑草-7 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与7 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
前端郭德纲7 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR7 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式