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>
相关推荐
白菜__1 分钟前
去哪儿小程序逆向分析(酒店)
前端·javascript·爬虫·网络协议·小程序·node.js
前端老曹2 分钟前
Jspreadsheet CE V5 使用手册(保姆版) 二
开发语言·前端·vue.js·学习
老华带你飞8 分钟前
动物救助|流浪狗救助|基于Springboot+vue的流浪狗救助平台设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·流浪动物救助平台
困惑阿三24 分钟前
深入理解 JavaScript 中的(Promise.race)
开发语言·前端·javascript·ecmascript·reactjs
我命由我1234526 分钟前
微信小程序 bind:tap 与 bindtap 的区别
开发语言·前端·javascript·微信小程序·小程序·前端框架·js
5335ld30 分钟前
vue2 直播地址播放 兼容浏览器
前端·vue.js
克喵的水银蛇31 分钟前
Flutter 布局实战:掌握 Row/Column/Flex 弹性布局
前端·javascript·flutter
哆啦A梦158837 分钟前
60 订单页选择收货地址
前端·javascript·vue.js·node.js
馬致远1 小时前
案例1- 跳动的心
javascript·css·css3
Hilaku1 小时前
利用 link rel="prefetch":如何让用户的页面秒开?
前端·javascript·性能优化