1.前端逻辑
本项目基于之前搭建的vite环境:https://blog.csdn.net/beekim/article/details/128083106?spm=1001.2014.3001.5501
新增一个登录页和聊天室页面
<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>
<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
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文件),然后执行以下两条命令
npm init -yyarn add ws
index.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
还需调整聊天室页面的代码为:
<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>
开启两个窗口就可以测试了,可以基于此代码优化各种细节