websocket+node+vite(vue)实现一个简单的聊天

1.前端逻辑

本项目基于之前搭建的vite环境:https://blog.csdn.net/beekim/article/details/128083106?spm=1001.2014.3001.5501

新增一个登录页和聊天室页面

html 复制代码
<template>
  <div>登录页</div>
  <div>
    用户名:<input type="text" placeholder="请输入用户名" v-model="username" /><br />
    <button @click="enter">进入聊天室</button>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useRouter } from "vue-router";
const username = ref();

const { replace } = useRouter();

onMounted(() => {
  username.value = localStorage.getItem("_username");
  if (username.value) {
    replace({ path: "/chatRoom" });
  }
});

const enter = () => {
  const _username = username.value.trim();
  if (_username.length > 0) {
    localStorage.setItem("_username", _username);//缓存当前登录人
    replace({ path: "/chatRoom" });
  }
};
</script>
<style scoped lang="less"></style>
html 复制代码
<template>
  <div>聊天室</div>
  <div class="msg-list" v-if="msgList">
    <div v-for="(item, index) in msgList" :key="index">
      <div>
        <span>{{ item.user }}</span>
        <span>{{ item.date }}</span>
      </div>
      <div>消息:{{ item.msg }}</div>
    </div>
  </div>
  <div>
    <input type="text" placeholder="请输入消息" v-model="msg" />
    <button @click="send">发送</button>
  </div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const msgList = ref<any>([]);
const msg = ref();

const send = () => {
  if (!msg.value.trim().length) return;

   msgList.value.push({
     id: new Date().getTime(),
     user: localStorage.getItem("_username"),
     date: new Date(),
     msg: msg.value,
   });

};
</script>
<style scoped lang="less"></style>

2.封装websocket

js 复制代码
const useWebSocket = (handleMessage: any) => {
  const ws = new WebSocket('ws://localhost:8000');
  const init = () => {
    bindEvent();
  };

  function bindEvent() {
    ws.addEventListener("open", handleOpen, false);
    ws.addEventListener("close", handleClose, false);
    ws.addEventListener("error", handleError, false);
    ws.addEventListener("message", handleMessage, false);
  }
  function handleOpen(e) {
    console.log("WebSocket open", e);
  }
  function handleClose(e) {
    console.log("WebSocket open", e);
  }
  function handleError(e) {
    console.log("WebSocket open", e);
  }

  init();
  return ws;
};

export { useWebSocket };

3.后端(node)逻辑

先在根目录建一个server文件夹,在下面建一个index.js文件(node需要js文件才可以执行,别建ts文件),然后执行以下两条命令

js 复制代码
npm init -y

yarn add ws

index.js

js 复制代码
console.log("测试websocket");
const WebSocket = require("ws");
((Ws) => {
  const server = new Ws.Server({ port: 8000 });

  const init = () => {
    bindEvent();
  };
  function bindEvent() {
    server.on("open", handleOpen);
    server.on("close", handleClose);
    server.on("error", handleError);
    server.on("connection", handleConnection);
  }

  function handleOpen() {
    console.log("webscoket  open");
  }
  function handleClose() {
    console.log("webscoket  close");
  }
  function handleError() {
    console.log("webscoket  error");
  }
  function handleConnection(ws) {
    console.log("webscoket connection");
    ws.on("message", handleMsg);
  }
  function handleMsg(msg) {
    console.log(JSON.parse(msg));
    server.clients.forEach((c) => {
      c.send(msg); //广播消息
    });
  }

  init();
})(WebSocket);

4.测试

在测试之前需启动后台

执行node index.js

还需调整聊天室页面的代码为:

html 复制代码
<template>
  <div>聊天室</div>
  <div class="msg-list" v-if="msgList">
    <div v-for="(item, index) in msgList" :key="index">
      <div>
        <span>{{ item.user }}</span>
        <span>{{ item.date }}</span>
      </div>
      <div>消息:{{ item.msg }}</div>
    </div>
  </div>
  <div>
    <input type="text" placeholder="请输入消息" v-model="msg" />
    <button @click="send">发送</button>
  </div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useWebSocket } from "@/hooks/index";
const msgList = ref<any>([]);
const msg = ref();

// {
//   id: new Date().getTime(),
//   user:localStorage.getItem('_username'),
//   date:new Date().getTime(),
//   msg:'bbbbb'
// }
const handleMessage = (e) => {
  console.log(e);
  // const _msgData = JSON.parse(e.data);
  // console.log(_msgData);

//因为从后台接收到的数据是blob类型的值,所以转换一下
  e.data.text().then((v) => {
    console.log(v);
    msgList.value.push(JSON.parse(v));
  });
  // msgList.value.push(_msgData);
};
const ws = useWebSocket(handleMessage);

const send = () => {
  if (!msg.value.trim().length) return;

  //   msgList.value.push({
  //     id: new Date().getTime(),
  //     user: localStorage.getItem("_username"),
  //     date: new Date(),
  //     msg: msg.value,
  //   });
  ws.send(
    JSON.stringify({
      id: new Date().getTime(),
      user: localStorage.getItem("_username"),
      date: new Date(),
      msg: msg.value,
    })
  );
};
</script>
<style scoped lang="less"></style>

开启两个窗口就可以测试了,可以基于此代码优化各种细节

相关推荐
Gracemark11 小时前
高德地图-地图选择经纬度问题【使用输入提示-使用Autocomplete进行联想输入】(复盘)
vue.js
天下无贼13 小时前
【手写组件】 Vue3 + Uniapp 手写一个高颜值日历组件(含跨月补全+今日高亮+选中状态)
前端·vue.js
洋葱头_14 小时前
vue3项目不支持低版本的android,如何做兼容
前端·vue.js
奔跑的蜗牛ing14 小时前
Vue3 + Element Plus 输入框省略号插件:零侵入式全局解决方案
vue.js·typescript·前端工程化
最后一个农民工16 小时前
vue3实现仿豆包模版式智能输入框
前端·vue.js
艾小码20 小时前
Vue组件到底怎么定义?全局注册和局部注册,我踩过的坑你别再踩了!
前端·javascript·vue.js
wusp199420 小时前
项目实战——“微商城”前后台【005】之前台项目首页编写
vue.js·vant·底部导航栏
森林的尽头是阳光21 小时前
vue防抖节流,全局定义,使用
前端·javascript·vue.js
计算机毕业设计木哥21 小时前
计算机毕设选题推荐:基于Java+SpringBoot物品租赁管理系统【源码+文档+调试】
java·vue.js·spring boot·mysql·spark·毕业设计·课程设计
zero13_小葵司21 小时前
Vue 3 前端工程化规范
前端·javascript·vue.js