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>
相关推荐
晴殇i14 分钟前
前端鉴权新时代:告别 localStorage,拥抱更安全的 JWT 存储方案
前端·javascript·面试
Json____16 分钟前
使用node Express 框架框架开发一个前后端分离的二手交易平台项目。
java·前端·express
码农刚子23 分钟前
ASP.NET Core Blazor简介和快速入门 二(组件基础)
javascript·后端
我是日安1 小时前
从零到一打造 Vue3 响应式系统 Day 27 - toRef、toRefs、ProxyRef、unref
前端·javascript·vue.js
Q_Q19632884751 小时前
python+vue的在线租房 房屋租赁系统
开发语言·vue.js·spring boot·python·django·flask·node.js
不如喫茶去1 小时前
VUE查询-历史记录功能
前端·javascript·vue.js
武天2 小时前
说说你对slot的理解?slot使用场景有哪些?
vue.js
一枚前端小能手2 小时前
「周更第8期」实用JS库推荐:decimal.j
前端·javascript
武天2 小时前
vue中,key的原理
vue.js
武天2 小时前
如何打破scope对样式隔离的限制?
vue.js