webSocket 聊天室 node.js 版

全局安装vue脚手架 npm install @vue/cli -g

创建 vue3 + ts 脚手架 vue create vue3-chatroom

后端代码

src 同级目录下建 server:

javascript 复制代码
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);

const io = require('socket.io')(server, { cors: true })

io.on('connection', (socket) => {
  console.log('socket 已连接');

  socket.on('sendToServer', data => {
    console.log(`收到了前端发来的消息: ${data}`);
    io.emit("sendToClient", data);
  })
  socket.on('disconnect', () => {
    console.log('断开连接');
  });
});



server.listen(3000, () => {
  console.log('listening on *:3000');
});

前端代码

核心代码:

javascript 复制代码
import io from 'socket.io-client'

var socket = io('ws://localhost:3000')

socket.on("sendToClient", data => {
  console.log(`收到了后端发来的数据:${data}`);

  records.value.push(JSON.parse(data))
})

const sendMessage = () => {
  if (!message.value.trim()) return
  const record: IRecord = reactive({
    message: message.value,
    nickname,
    userId: new Date().getTime() + '',
    color: '',
    sendTime: getYMDHMS(new Date().getTime())
  })


  socket.emit('sendToServer', JSON.stringify(record));


  message.value = '';
}

完整代码:

javascript 复制代码
<template>
  <div class="chat-room">
    <div class="nav"></div>
    <div class="main">
      <div class="title">
        <span>图灵聊天室({{ userCount }})</span>
      </div>
      <div class="content" ref="recordsContent">
        <div v-for="(itm, inx) in records" :key="inx">
          <div
            class="item"
            :class="[itm.nickname === nickname ? 'item' : 'item-other']"
          >
            <div class="info">[ {{ itm.nickname }}:{{ itm.sendTime }} ]</div>
            <span class="message">{{ itm.message }}</span>
          </div>
        </div>
      </div>
      <div class="input-box">
        <div class="text">
          <textarea :rows="8" v-model="message" @keydown="onKeydown"></textarea>
        </div>
        <div class="opt">
          <button ghost @click="sendMessage">发 送</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import io from 'socket.io-client'
import { reactive, ref } from 'vue'

interface IRecord {
  nickname: string,
  userId: string,
  color: string,
  message: string,
  sendTime: string
}
const userCount = ref(2)
const records = ref<IRecord[]>([])
const message = ref('')
const nickname = localStorage.getItem('username') || '匿名用户'

var socket = io('ws://localhost:3000')



socket.on("sendToClient", data => {
  console.log(`收到了后端发来的数据:${data}`);
  records.value.push(JSON.parse(data))
})

const sendMessage = () => {
  if (!message.value.trim()) return
  const record: IRecord = reactive({
    message: message.value,
    nickname,
    userId: new Date().getTime() + '',
    color: '',
    sendTime: getYMDHMS(new Date().getTime())
  })
  socket.emit('sendToServer', JSON.stringify(record));
  message.value = '';
}

const onKeydown = (event: any) => {
  if (event.keyCode === 13) {
    sendMessage()
  }
}

function getYMDHMS(timestamp:number) {
  let time = new Date(timestamp)
  let year = time.getFullYear()
  let month:any = time.getMonth() + 1
  let date:any = time.getDate()
  let hours:any = time.getHours()
  let minute:any = time.getMinutes()
  let second:any = time.getSeconds()

  if (month < 10) { month = '0' + month }
  if (date < 10) { date = '0' + date }
  if (hours < 10) { hours = '0' + hours }
  if (minute < 10) { minute = '0' + minute }
  if (second < 10) { second = '0' + second }
  return year + '-' + month + '-' + date + ' ' + hours + ':' + minute + ':' + second
}
  
</script>

<style scoped lang="scss">
.chat-room {
  margin: 0px auto;
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: row;
  border: 1px solid #ccc;
  overflow: hidden;
  .nav {
    width: 66px;
    background: #363636;
    flex-shrink: 0;
  }

  .main {
    display: flex;
    background: #efefef;
    flex: 1;
    width: 0;
    display: flex;
    flex-direction: column;

    .title {
      height: 60px;
      display: flex;
      align-items: center;
      font-size: 16px;
      font-weight: 700;
      padding-left: 20px;
      border-bottom: 1px solid #c3c3c3;
      flex-shrink: 0;
    }

    .content {
      flex: 1;
      height: 0px;
      position: relative;
      overflow-y: auto;
      padding: 10px;

      .item {
        text-align: right;
        .info {
          font-size: 14px;
          color: #666;
        }
        .message {
          font-size: 18px;
          background-color: rgba(110, 89, 228, 0.579);
          margin: 10px;
          padding: 8px 12px;
          border-radius: 8px;
          display: inline-block;
          color: #333;
        }
      }
      .item-other {
        text-align: left;
        .message {
          background-color: rgb(218, 197, 112);
        }
      }
    }

    .input-box {
      height: 230px;
      border-top: 1px solid #c3c3c3;
      flex-shrink: 0;
      display: flex;
      flex-direction: column;

      .text {
        flex: 1;

        textarea {
          width: 94%;
          height: 160px;
          font-size: 16px;
          resize: none;
          border: none;
          padding: 8px 24px;
          background: #efefef;

          &:focus {
            outline: none;
          }

          &:focus-visible {
            outline: none;
          }
        }
      }

      .opt {
        height: 60px;
        flex-shrink: 0;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        padding-right: 20px;
      }
    }
  }
}
</style>
相关推荐
SKH.10 小时前
网络(3)TCP通信
网络·网络协议·tcp/ip
MetaLite11 小时前
HTTPS之外的响应加密-GCM序列化与处理器顺序
网络协议·http·https
百万运营Pro11 小时前
用 Astro + Supabase 从零构建全网盘聚合搜索引擎:PGroonga 中文检索实战
搜索引擎·前端框架·node.js·个人开发·学习方法·ai编程·资源分享
姚不倒11 小时前
HAProxy 系列(二):健康检查与 SSL 卸载 — 保障可用性与性能
运维·网络·网络协议·ssl·haproxy
蕾米莉亚《'';12 小时前
ip与dns科普向
网络协议·tcp/ip
美酒没故事°12 小时前
是tls、https、waf
网络协议·http·https
鲨鱼辣钊1 天前
FastAPI进阶_Day21_WebSocket实时通讯实战
websocket·网络协议·fastapi
小婉1 天前
我用 Next.js + React Flow 从零搭建了一个可视化 AI 工作流编排平台
前端·人工智能·node.js
2501_915106321 天前
安卓抓包软件2026,免证书抓包 应用层抓包 代理抓包全解析
网络协议·计算机网络·网络安全·ios·adb·https·udp
Neighbor_OldY1 天前
云上VPC流日志与网络流量安全分析实战:异常流量、横向移动、C2外连与恶意IP的发现与处置
网络协议·tcp/ip·安全