webSocket 聊天室 node.js 版
全局安装vue脚手架 npm install @vue/cli -g
创建 vue3 + ts 脚手架 vue create vue3-chatroom
后端代码
src 同级目录下建 server:

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');
});
前端代码
核心代码:
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()) returnconst 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 = '';
}
完整代码:
<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"><divclass="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()) returnconst 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() + 1let 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>
相关文章:
webSocket 聊天室 node.js 版
全局安装vue脚手架 npm install vue/cli -g 创建 vue3 ts 脚手架 vue create vue3-chatroom 后端代码 src 同级目录下建 server: const express require(express); const app express(); const http require(http); const server http.createServer(app);const io req…...
iptables防火墙(SNAT与DNAT)
目录 1 SNAT 1.1 SNAT原理与应用 1.2 SNAT工作原理 1.3 SNAT转换前提条件 2 SNAT示例 编辑 2.1 网关服务器配置 2.1.1 网关服务器配置网卡 2.1.2 开启SNAT命令 2.2 内网服务器端配置 2.3 外网服务器端配置 2.4 网卡服务器端添加规则 2.5 SNAT 测试 3 DNAT 3.1 网卡…...
第 359 场 LeetCode 周赛题解
A 判别首字母缩略词 签到题… class Solution { public:bool isAcronym(vector<string> &words, string s) {string pf;for (auto &s: words)pf.push_back(s[0]);return pf s;} };B k-avoiding 数组的最小总和 贪心:从 1 1 1开始升序枚举,…...
【开源项目】Stream-Query的入门使用和原理分析
前言 无意间发现了一个有趣的项目,Stream-Query。了解了一下其基本的功能,可以帮助开发者省去Mapper的编写。在开发中,我们会编写entity和mapper来完成业务代码,但是Stream-Query可以省去mapper,只写entity。 快速入…...
微信小程序picker组件的简单使用 单选
<picker mode"selector" range"{{classData}}" bindchange"bindClassChange" value"{{classIndex}}" range-key"className"><view class"picker">{{classData[classIndex].className || 请选择班级}}…...
python、numpy、pytorch中的浅拷贝和深拷贝
1、Python中的浅拷贝和深拷贝 import copya [1, 2, 3, 4, [11, 22, 33, [111, 222]]] b a c a.copy() d copy.deepcopy(a)print(before modify\r\n a\r\n, a, \r\n,b a\r\n, b, \r\n,c a.copy()\r\n, c, \r\n,d copy.deepcopy(a)\r\n, d, \r\n)before modify a [1, 2…...
EasyRecovery14数据恢复软件支持各类存储设备的数据恢复
EasyRecovery14数据恢复软件专业数据恢复软件支持电脑、相机、移动硬盘、U盘、SD卡、内存卡、光盘、本地电子邮件和 RAID 磁盘阵列等各类存储设备的数据恢复。 目前市面上有许多数据恢复软件,但褒贬不一,而且数据恢复软件又不是一款会被经常使用的软件&a…...
玩机搞机----面具模块的组成 制作模块
root面具相信很多玩家都不陌生。早期玩友大都使用第三方卡刷补丁来对系统进行各种修复和添加功能。目前面具补丁代替了这些操作。今天的帖子了解下面具各种模块的组成和几种普遍的代码组成。 Magisk中运行的每个单独的shell脚本都将在内部的BusyBox的shell中执行。对于与第三方…...
注册中心/配置管理 —— SpringCloud Consul
Consul 概述 Consul 是一个可以提供服务发现,健康检查,多数据中心,key/Value 存储的分布式服务框架,用于实现分布式系统的发现与配置。Cousul 使用 Go 语言实现,因此天然具有可移植性,安装包仅包含一个可执…...
Next.js 13 你需要了解的 8 件事
目录 React 服务器组件 (RSC)服务器组件默认开启在 Next.js 中客户端组件也在服务器上呈现!组成客户端和服务器组件编译Next.js 13 渲染模式桶文件有点坏了库集成:WIP 仍在进行中Route groups 路由组总结 在本文中,我们…...
计数排序(Count Sort)算法详解
1. 算法简介 计数排序(Count Sort)是一种非比较排序算法,其核心思想是统计数组中每个元素出现的次数,然后根据统计结果将元素按照顺序放回原数组中。计数排序的时间复杂度为O(nk),其中n是数组的长度,k是数…...
Linux驱动开发(Day3)
驱动点灯:...
使用Vscode调试shell脚本
在vcode中安装bash dug插件 在vcode中添加launch.json配置,默认就好 参考:http://www.rply.cn/news/73966.html 推荐插件: shellman(支持shell,智能提示) shellcheck(shell语法检查) shell-format(shell格式化)...
OpenAI Function calling
开篇 原文出处 最近 OpenAI 在 6 月 13 号发布了新 feature,主要针对模型进行了优化,提供了 function calling 的功能,该 feature 对于很多集成 OpenAI 的应用来说绝对是一个“神器”。 Prompt 的演进 如果初看 OpenAI 官网对function ca…...
【C语言】字符分类函数、字符转换函数、内存函数
前言 之前我们用两篇文章介绍了strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp、strstr、strtok、streeror这些函数 第一篇文章strlen、strcpy、stract 第二篇文章strcmp、strncpy、strncat、strncmp 第三篇文章strstr、strtok、streeror 今天我们就来学习字…...
Deep Learning With Pytorch - 最基本的感知机、贯序模型/分类、拟合
文章目录 如何利用pytorch创建一个简单的网络模型?Step1. 感知机,多层感知机(MLP)的基本结构Step2. 超平面 ω T ⋅ x b 0 \omega^{T}xb0 ωT⋅xb0 or ω T ⋅ x b \omega^{T}xb ωT⋅xb感知机函数 Step3. 利用感知机进行决策…...
测试工具coverage的高阶使用
在文章Python之单元测试使用的一点心得中,笔者介绍了自己在使用Python测试工具coverge的一点心得,包括: 使用coverage模块计算代码测试覆盖率使用coverage api计算代码测试覆盖率coverage配置文件的使用coverage badge的生成 本文在此基础上…...
安卓监听端口接收消息
文章目录 其他文章监听端口接收消息 建立新线程完整代码 其他文章 下面是我的另一篇文章,是在电脑上发送数据,配合本篇文章,可以实现电脑与手机的局域网通讯。直接复制粘贴就能行,非常滴好用。 点击连接 另外,如果你不…...
「Node」下载安装配置node.js
以下是Node.js的下载、安装和配置的全面教程: 下载 Node.js 打开 Node.js 官方网站:Previous Releases在主页上,您会看到两个版本可供选择:LTS(长期支持版本)和最新版(Current)。如…...
NOIP2014普及组,提高组 比例简化 飞扬的小鸟 答案
比例简化 说明 在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结果。例如,对某一观点表示支持的有1498 人,反对的有 902人,那么赞同与反对的比例可以简单的记为1498:902。 不过,如果把调查结果就以这种…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
