【你的第二个socket应用】Vue3+Node实现一对一即时聊天应用

简介: 上一篇文章通过WebSocket实现了一个即时通讯聊天室,使用是Vue3+Node,那篇文章点我进入,这篇文章在上一篇文章的基础上进行一个简单的扩展,实现一个一对一即时聊天应用。
Hi~,我是 一碗周,一个在舒适区垂死挣扎的前端,如果写的文章有幸可以得到你的青睐,万分有幸~

🍑 写在前面

前一段时间通过WebSocket实现了一个即时通讯聊天室,使用是Vue3+Node,那篇文章点我进入,这篇文章在上一篇文章的基础上进行一个简单的扩展,实现一个一对一即时聊天应用。

注:这篇文章完全是在上一篇的基础上进行的,直接看的话可能会懵逼。

运行效果如下图所示:

私聊功能_EbvC0kK2Rq.gif

🍓 组件的编写

🍇 私聊组件的编写

这里完全是在上一篇文章的基础上进行的,这里只需要扩展一个抽屉组件就可以了,上图中私聊的组件是复用的群聊组件,实现代码如下:

<script setup lang="ts">
import { computed, ref } from 'vue'

interface Props {
  modelValue: boolean
}
const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const aniShow = ref(false)
const show = computed({
  get() {
    aniShow.value = props.modelValue
    return props.modelValue
  },
  set(v) {
    emitUpdate(v)
  },
})
const emitUpdate = (v: boolean, time = 300) => {
  aniShow.value = v
  window.setTimeout(() => {
    emit('update:modelValue', v)
  }, time)
}
</script>
<template>
  <div class="ywz-drawer h-screen w-screen fixed z-10 top-0" v-show="show">
    <div
      class="drawer-overlay absolute inset-0 z-0"
      @click="emitUpdate(false)"
    ></div>
    <Transition>
      <div
        v-show="aniShow"
        class="drawer-content absolute right-0 top-0 cursor-default h-screen bg-base-100"
      >
        <slot></slot>
      </div>
    </Transition>
  </div>
</template>
<style scoped>
.drawer-overlay {
  --tw-bg-opacity: 0.4;
  opacity: 0.999999;
  cursor: pointer;
  background-color: hsl(var(--nf, var(--n)) / var(--tw-bg-opacity));
  transition: all 0.3s;
}
.v-enter-active,
.v-leave-active {
  transition: all 0.3s;
}

.v-enter-from,
.v-leave-to {
  transform: translateX(100%);
}
</style>

这个组件我们通过v-model的方式实现抽屉的打开与关闭,这里还为组件的进入的退出增加了一个过渡效果。

🍅 NavHeader组件的修改

这里我们在NavHeader组件的头部展示了用户的头像,如果存在新消息(通过new属性来判断)则展示一个绿色的圆点,点击头像触发一个事件,告诉父组件可以进行操作,实现代码如下:

<script setup lang="ts">
import { computed } from 'vue'

interface Props {
  groupName: string
  personNumber: number
  userList: Map<any, any>
  curUserId: string
}
interface User {
  id: string
  avatar: string
  name: string
  new: boolean
}
const props = defineProps<Props>()
const emit = defineEmits(['more'])
const handleMore = (user: User) => {
  emit('more', user)
}
const users = computed<User[]>(() => {
  const list: User[] = []
  if (props.userList.size === 0) return []
  props.userList.forEach((value, key) => {
    if (key !== props.curUserId) {
      list.push({
        avatar: value.avatar,
        id: key,
        name: value.name,
        new: value.new,
      })
    }
  })
  return list
})
</script>

<template>
  <!-- 顶部栏 -->
  <div class="navbar text-primary-content rounded-box space-x-1 h-16">
    <div class="flex-1">
      <a class="normal-case text-xl pl-4"
        >{{ props.groupName }}({{ props.personNumber }})</a
      >
    </div>
    <div class="flex-none avatar-list pr-4">
      <div
        class="avatar ml-1 cursor-pointer"
        :class="item.new ? 'online' : ''"
        @click="handleMore(item)"
        v-for="item in users"
        :key="item.id"
      >
        <div class="w-6 rounded-full">
          <img :src="item.avatar" />
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped></style>

🍍 服务端的实现

服务端这里比较好实现,主要是监听消息的发送以及告诉客户端谁给谁发送了消息,实现代码如下:

socket.on('send-user', e => {
  const sendUserId = e.sendUserId
  socket.to(sendUserId).emit('message-user', e)
})
  • 首先我们通过监听send-user事件,监听用户什么时候发送私聊消息;
  • 发送消息后我们获取到发送给某个用户的id;
  • 最后我们将这个消息通过to的方式指定的发出一个message-user的事件,告诉他谁给他发的消息。

🍈 客户端的实现

现在我们就根据上面打下的基础,来编写客户端。

🍉 定义变量与基础方法

首先我们先定义变量以及数据结构,代码如下:

interface User {
  name: string
  avatar: string
  id: string
  new: boolean
}
// 控制控制的显示与隐藏
const drawerShow = ref(false)
// 与所有用户私聊的内容存储单元
const userChatData = ref<Map<string, ChatDataItem[]>>(new Map())
// 正在私聊的用户id
const chatUserId = ref('')
// 私聊聊天框的文字内容
const userMessage = ref('')
// 打开抽屉
const handleOpenDrawer = (user: typeof curUser) => {
  drawerShow.value = true
}
// 私聊发送消息
const handleSendUser = (v: string) => {
  const obj = {}
  // 发送消息
  socket.emit('send-user', obj)
}
// 监听接受消息
socket.on('message-user', (e: any) => {
  
})

这里我们通过数据结构来存储用户的聊天记录,这里也可以使用普通对象存储,这里我为了后续方便扩展我使用了Map

🍒 实现私聊窗口的打开

实现私聊窗口打开非常的容易,实现代码如下:

const handleOpenDrawer = (user: typeof curUser) => {
  chatUserId.value = user.id
  // 清空头像右上角的绿色圆圈
  const u = userList.value.get(chatUserId.value)
  if (u) {
    u.new = false
  }
  drawerShow.value = true
}

🍐 实现私聊消息的发送

私聊发送消息几乎与群聊发送消息一致,不同的是需要传递接收消息那个人的id以及保存的位置也所有不同,实现代码如下:

const handleSendUser = (v: string) => {
  const obj = {
    id: Math.random().toString().split('.')[1].slice(0, 10),
    name: curUser.name,
    avatar: curUser.avatar,
    content: v,
    userId: curUser.id,
    sendUserId: chatUserId.value,
  }
  // 在 userChatData 中新增一条数据,表示自己发送的
  const type: 'me' = 'me'
  // 判断是否与该用户聊过天,如果没有创建一个空的聊天记录
  if (!userChatData.value.has(chatUserId.value)) {
    userChatData.value.set(chatUserId.value, [])
  }
  // 获取聊天记录,准备添加
  const _chatData = userChatData.value.get(chatUserId.value) ?? []
  _chatData.push(Object.assign({}, { type }, obj))
  // 清空 input box 中的内容
  userMessage.value = ''
  // 发出send事件,将消息发送出去
  socket.emit('send-user', obj)
}

🍏 实现消息的接收

接受消息也比较简单,首选确定是谁发送的消息,然后将其添加到指定用户的聊天记录中即可。

socket.on('message-user', (e: any) => {
  const msg = Object.assign({}, e, { type: 'your' }) as ChatDataItem
  const sendId = e.userId
  if (!userChatData.value.has(sendId)) {
    userChatData.value.set(sendId, [])
  }
  const chatData = userChatData.value.get(sendId) ?? []
  chatData.push(msg)
  // 设置小绿点
  const u = userList.value.get(sendId)
  if (u) {
    u.new = true
  }
})

🥭 写在最后

到这为止我们就实现了简单的私聊功能,由于该篇文章与上一篇文章【你的第一个socket应用】Vue3+Node实现一个WebSocket即时通讯聊天室,有非常强的联系,所有需要先阅读过前面的那一篇。

上面的代码还有好多的可以优化的点,比如在群聊中点击头像可以私聊等(这个功能我已经实现,可以在GitHub中找到参考)。

创作不易,如果可以三连支持一下,你的三连是我持续输出的动力😜😜

023B982F_CGmCSC7VVJ.gif

目录
相关文章
|
2天前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
24 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
3月前
|
监控 JavaScript 算法
如何使用内存监控工具来定位和解决Node.js应用中的性能问题?
总之,利用内存监控工具结合代码分析和业务理解,能够逐步定位和解决 Node.js 应用中的性能问题,提高应用的运行效率和稳定性。需要耐心和细致地进行排查和优化,不断提升应用的性能表现。
220 77
|
27天前
|
JavaScript 前端开发 jenkins
抛弃node和vscode,如何用记事本开发出一个完整的vue前端项目
本文探讨了在不依赖Node和VSCode的情况下,仅使用记事本和浏览器开发一个完整的Vue3前端项目的方法。通过CDN引入Vue、Vue Router、Element-UI等库,直接编写HTML文件实现页面功能,展示了前端开发的本质是生成HTML。虽然日常开发离不开现代工具,但掌握这种基础方法有助于快速实现想法或应对特殊环境限制。文章还介绍了如何用Node简单部署HTML文件到服务器,提供了一种高效、轻量的开发思路。
53 10
|
3月前
|
存储 缓存 JavaScript
如何优化Node.js应用的内存使用以提高性能?
通过以上多种方法的综合运用,可以有效地优化 Node.js 应用的内存使用,提高性能,提升用户体验。同时,不断关注内存管理的最新技术和最佳实践,持续改进应用的性能表现。
171 62
|
2月前
|
监控 算法 JavaScript
基于 Node.js Socket 算法搭建局域网屏幕监控系统
在数字化办公环境中,局域网屏幕监控系统至关重要。基于Node.js的Socket算法实现高效、稳定的实时屏幕数据传输,助力企业保障信息安全、监督工作状态和远程技术支持。通过Socket建立监控端与被监控端的数据桥梁,确保实时画面呈现。实际部署需合理分配带宽并加密传输,确保信息安全。企业在使用时应权衡利弊,遵循法规,保障员工权益。
51 7
|
3月前
|
存储 缓存 监控
如何使用内存监控工具来优化 Node.js 应用的性能
需要注意的是,不同的内存监控工具可能具有不同的功能和特点,在使用时需要根据具体工具的要求和操作指南进行正确使用和分析。
91 31
|
3月前
|
JavaScript 前端开发 API
深入理解Node.js事件循环及其在后端开发中的应用
本文旨在揭示Node.js的核心特性之一——事件循环,并探讨其对后端开发实践的深远影响。通过剖析事件循环的工作原理和关键组件,我们不仅能够更好地理解Node.js的非阻塞I/O模型,还能学会如何优化我们的后端应用以提高性能和响应能力。文章将结合实例分析事件循环在处理大量并发请求时的优势,以及如何避免常见的编程陷阱,从而为读者提供从理论到实践的全面指导。
|
3月前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
75 3
|
3月前
|
Web App开发 JSON JavaScript
Node.js 中的中间件机制与 Express 应用
Node.js 中的中间件机制与 Express 应用
|
6天前
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
Node.js 是一种高效的 JavaScript 运行环境,基于 Chrome V8 引擎,支持在服务器端运行 JavaScript 代码。本文介绍如何在阿里云上一键部署 Node.js 环境,无需繁琐配置,轻松上手。前提条件包括 ECS 实例运行中且操作系统为 CentOS、Ubuntu 等。功能特点为一键安装和稳定性好,支持常用 LTS 版本。安装步骤简单:登录阿里云控制台,选择扩展程序管理页面,安装 Node.js 扩展,选择实例和版本,等待创建完成并验证安装成功。通过阿里云的公共扩展,初学者和经验丰富的开发者都能快速进入开发状态,开启高效开发之旅。

热门文章

最新文章