前端实现websocket(vue3)

2023-11-09

在config/index.js文件中配置一下websocket

// websocket的域名和端口号的配置
const BASE_URL = 'localhost';
const WS_PORT = '8080';
const WS_ADDRESS = `ws://${BASE_URL}:${WS_PORT}`;

export const useWebsockt = (handleMessage) => {
  const ws = new WebSocket(WS_ADDRESS );

  //ws.binaryType = 'arraybuffer'; //可将 WebSocket 对象的 binaryType 属性设为“blob”或“arraybuffer”。默认格式为“blob”(您不必在发送时校正 binaryType 参数)。
  const init = () => {
    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 close', e);
  }

  function handleError(e) {
    console.log('WebSocket error', e);
  }

  init();
  return ws;
};

在页面中使用websocket
在这里插入图片描述
页面代码如下:

<template>
  <div class="body-content">
    <div class="web-socket">
      <header class="header">聊天室</header>
      <main class="main-content">
        <block v-for="(item, index) in msgListSelf" :key="index">
          <!-- business -->
          <div class="business" :key="index" v-if="!item.right">
            <div class="business-left">
              <img
                class="business-img header-img"
                src="https://qiyukf.com/sdk/res/skin/default/ico-kefu@2x.png?imageView&type=png%7CimageView&thumbnail=76y76&axis=5"
                alt=""
              />
              <ul>
                <p class="icon business-icon"></p>
                <p class="chat-content">{{ item.msg }}</p>
              </ul>
              <p class="curent-time">{{ getTime(item.curentTime) }}</p>
            </div>
          </div>

          <!-- user -->
          <div class="userSelf" :key="index + 10000" v-else>
            <div class="user-right">
              <ul>
                <p class="chat-content">{{ item.msg }}</p>
                <p class="icon userSelf-icon"></p>
              </ul>
              <img
                class="userSelf-img header-img"
                src="https://qiyukf.com/sdk/res/skin/default/ico-kefu@2x.png?imageView&type=png%7CimageView&thumbnail=76y76&axis=5"
                alt=""
              />
              <p class="curent-time">{{ getTime(item.curentTime) }}</p>
            </div>
          </div>
        </block>
      </main>

      <footer class="footer">
        <!-- contenteditable="true"标签可以编辑 -->
        <textarea
          contenteditable="true"
          @keydown="keydownCode"
          v-model="msg"
          placeholder="请您输入内容"
        ></textarea>
        <button @click="msgBtnClick">发送</button>
      </footer>
    </div>
  </div>
</template>

<script >
import { reactive, ref, toRefs } from "vue";
import { useWebsockt } from "../../hooks";
import { useRoute } from "vue-router";

export default {
  setup(params) {
    // 接收路由跳转携带参数
    const Route = useRoute();
    const username = Route.query.username;
    console.log("参数", username);

    const state = reactive({
      msg: "",
      msgListSelf: [],
    });

    // 接收到socket的实时数据
    const ws = useWebsockt(handleMessage);
    // 解析Blob进制流
    const reader = new FileReader();

    // 接收实时的数据
    function handleMessage(evt) {
      if (evt.data) {
        isBlob(evt.data);
      }
    }

    // 获取时间
    function getTime(time) {
      const oDate = new Date(time); //实例一个时间对象;
      const year = oDate.getFullYear(); //获取系统的年;
      const month = oDate.getMonth() + 1; //获取系统月份,由于月份是从0开始计算,所以要加1
      const date = oDate.getDate(); // 获取系统日,
      const h = oDate.getHours(); //获取系统时,
      const m = oDate.getMinutes(); //分
      const s = oDate.getSeconds(); //秒

      return `${year}年${month}月${date}日 ${h}:${m}`;
    }

    // 是否返回是二进制流 默认是Blob类型的
    const isBlob = (data) => {
      let result = null;
      if (data instanceof Blob) {
        reader.readAsText(data, "UTF-8");
        reader.onload = (e) => {
          result = JSON.parse(reader.result);

          // 判断当前是本人 本人的话统一将数据排到右侧
          if (username === result.username) {
            result.right = true;
          }
          state.msgListSelf.push(result);
          console.log(state.msgListSelf);
        };
      }
      return result;
    };

    // 回车发送消息
    const keydownCode = (e) => {
      if (e.keyCode === 13) {
        msgBtnClick();
      }
    };

    // 点击发送消息
    const msgBtnClick = () => {
      const _msg = state.msg;
      if (!_msg.trim().length) return;

      //发送信息
      ws.send(
        JSON.stringify({
          id: new Date().getTime(),
          msg: _msg,
          curentTime: new Date().getTime(),
          username,
        })
      );

      state.msg = "";
    };
    function binarystate(ev) {
      return JSON.parse(
        new TextDecoder("utf-8").decode(new Uint8Array(ev.state))
      );
    }

    return {
      ...toRefs(state),
      msgBtnClick,
      getTime,
      keydownCode,
    };
  },
};
</script>

<style scoped>
* {
  padding: 0;
  margin: 0;
}

.body-content {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.web-socket {
  width: 500px;
  height: 500px;
  background: rgb(238, 235, 235);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden;
  border: 1px solid #ccc;
}

.header {
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f96868;
  font-size: 16px;
  color: #fff;
}

.main-content {
  flex: 1;
  padding: 15px 10px;
  overflow-y: auto;
}

.footer {
  height: 100px;
  border-top: 1px solid #ccc;
  background-color: #fff;
  display: flex;
  flex-direction: column;
  padding: 3px 6px;
  /* box-sizing: border-box; */
}

.footer textarea {
  min-height: 50px;
  border: none;
  resize: none;
  cursor: pointer;
  padding: 3px;
  margin-bottom: 10px;
  /* 去掉聚焦默认边框 */
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  -webkit-user-modify: read-write-plaintext-only;
  outline: none;
  box-shadow: none;
}

.footer button {
  width: 70px;
  height: 26px;
  background: crimson;
  opacity: 0.7;
  color: #fff;
  font-size: 14px;
  align-self: flex-end;
  border: none;
  border-radius: 5px;
}

.business {
  display: flex;
  justify-content: flex-start;
  margin-bottom: 25px;
  position: relative;
}

.userSelf {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 25px;
  position: relative;
}

.user-right {
  width: auto;
  display: flex;
}

.business-left {
  width: auto;
  display: flex;
}

.header-img {
  width: 38px;
  height: 38px;
  border-radius: 19px;
  background: aquamarine;
}

.userSelf-img {
  background: #f96868;
}

.business-left ul {
  position: relative;
  left: 10px;
  /* display: flex; */
  align-self: center;
  max-width: 400px;
  border-radius: 10px;
}

.user-right ul {
  position: relative;
  right: 10px;
  max-width: 400px;
  align-self: center;
  background: #f96868;
  border-radius: 10px;
}

.business-left .icon {
  left: -6px;
  border-right-width: 6px;
  border-right-color: #fff;
}

.user-right .icon {
  right: -6px;
  border-left-width: 6px;
  border-left-color: #f96868;
}

.icon {
  position: absolute;
  top: 10px;
  width: 0;
  height: 0;
  border: 0 solid #fff;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
}
.chat-content {
  background: #fff;
  border-radius: 10px;
  padding: 10px;
  max-width: 100%;
}

.user-right .chat-content {
  background: #f96868;
  color: #fff;
}
.business-left .curent-time {
  position: absolute;
  bottom: -22px;
  left: 48px;
  color: #000;
  opacity: 0.6;
  font-size: 12px;
}

.business-left .curent-username {
  left: 0;
  color: #000;
}
.curent-username {
  position: absolute;
  top: 43px;
  font-size: 12px;
  opacity: 0.6;
}

.user-right .curent-username {
  right: 0px;
  color: #f96868;
}

.user-right .curent-time {
  position: absolute;
  bottom: -22px;
  right: 48px;
  color: #f96868;
  opacity: 0.8;
  font-size: 12px;
}
</style>

以上逻辑涉及到是否是当前用户判断,好展示信息,从而加载不同样式布局,图暂时添加一个简单的用户名称窗口,这窗口填完之后跳转聊天窗。实际开发是根据登录用户信息来处理。
在这里插入图片描述

<template>
  <div class="chat-clients">
    <p class="chat-box">
      <input type="text" v-model="username" placeholder="请您输入聊天室昵称" />
      <button @click="entryChatClient">进入聊天室</button>
    </p>
  </div>
</template>

<script>
import { reactive, toRefs } from "vue";
import { useRouter } from "vue-router";

export default {
  setup() {
    const state = reactive({
      username: "",
    });

    const router = useRouter();

    const entryChatClient = () => {
      if (state.username) {
        router.push({
          path: "/websocket",
          query: { username: state.username },
        });
      }
    };
    return { entryChatClient, ...toRefs(state) };
  },
};
</script>

<style scoped>
.chat-clients {
  width: 100%;
  height: 100vh;
  background: #000;
  opacity: 0.8;
  display: flex;
  justify-content: center;
}

.chat-box {
  margin-top: 100px;
  width: 300px;
  height: 200px;
  border-radius: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.chat-box input {
  height: 50px;
  width: 200px;
}

.chat-box button {
  height: 50px;
  flex: 1;
}
</style>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

前端实现websocket(vue3) 的相关文章

  • 下载 csv 文件 node.js

    我正在使用 node js 构建一个应用程序并尝试将数据下载为 csv 文件 我正在使用 json2csv https www npmjs com package json2csv https www npmjs com package j
  • 纤维/未来实际上有什么作用?

    下面这行代码的作用是什么 Npm require fibers future 我在网上查找示例 发现了一些这样的示例 Future Npm require fibers future var accessToken new Future 什
  • javascript 是否有等效的 __repr__ ?

    我最接近Python的东西repr这是 function User name password this name name this password password User prototype toString function r
  • 使用socket.io进行用户身份验证

    我已经红色了这个教程 http howtonode org socket io auth http howtonode org socket io auth 它展示了如何使用express和socket io对用户进行身份验证 但是有没有一
  • 如何在查询语句之外从mysql查询中获取值?

    这是下面的函数console log function quo value value connection query SELECT role from roles where id 1 function error results fi
  • 对于实时网站使用 Node.js 或 Ringojs 安全吗?

    正如标题中所述 我想知道使用实际的 omg 平台 即 Node js 和 Ringo js 的实际版本 之一来开发网站是否安全 另外 我想知道他们是否支持cookie sessions以及他们如何处理多字段帖子 PHP中的fieldname
  • 在 Node 中使用 Babel 导入与请求 [重复]

    这个问题在这里已经有答案了 我想在一个文件中导入一个类 use strict import models from model class Foo bar export default new Foo 当我使用导入时它有效 例如 impor
  • 使用 React.js + Express.js 发送电子邮件

    我在 ES6 中使用 React js 构建了一个 Web 应用程序 我目前想要创建一个基本的 联系我们 页面并想要发送电子邮件 我是 React 新手 刚刚发现我实际上无法使用 React 本身发送电子邮件 我正在遵循教程nodemail
  • libxmljs 的替代品 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 目标 使用 Node js 访问网页 使用 xpath 语法操作 DOM 并打印新的 DOM libxm
  • Sequelize - 使用 es6 和模块运行迁移

    我不确定我是否做错了什么或者什么 我觉得我正在运行一个现代的 相当常见的堆栈 但我无法让新的 Sequelize v6 与我的设置完美配合 我在 Node v14 17 Sequelize v6 6 2 上 在我的 package json
  • Cosmos DB Mongo API 如何管理“请求率很大”情况

    我有以下代码 async function bulkInsert db collectionName documents try const cosmosResults await db collection collectionName
  • 如何使用Create React App安装React

    嗨 我对反应真的很陌生 我不知道如何实际安装它 也不知道我需要做什么才能在其中编写代码 我下载了node js并且安装了v12 18 3以及NPM 6 14 6 但是每次我尝试在许多网站上提到的create react app安装方法中输入
  • 使用 HTML5 或 Javascript 的 P2P 视频会议

    我正在尝试使用 html5 和 javascript 构建视频会议 直到现在我能够流式传输我的相机捕获并将其显示在画布上 这是代码
  • Node.js 和 Passport 对象没有 validPassword 方法

    我正在使用 Node js Express Passport 创建一个简单的身份验证 本地 到目前为止我所达到的效果是 当输入错误的用户名或密码时 用户将被重定向到错误页面 但是当用户输入正确的用户名和密码时 我收到此错误 node mod
  • 我的客户端 socket.io 在哪里?

    我使用 Express 和 React Engine 创建了一个同构 React 应用程序 现在我正在尝试连接socket io 在快速设置中我有 var express require express var app express va
  • 在 MongoDB 上,当我的回调位于“find”内部时,如何限制查询?

    我在 MongoDB 中有这个查询 db privateMessages find or fromId userId toId socket userId fromId socket userId toId userId function
  • Plesk Windows 部署 Node.js

    我创建了一个以 Node js 作为后端的 Angular 项目 这是服务器文件结构 Home directory httpdocs node hm dist browser folder server folder server js p
  • Mongoose 和 Promise:如何获取查询结果数组?

    使用猫鼬从数据库和 Q 中查询结果以获取承诺 但发现很难只获取可用用户列表 目前我有一些这样的东西 var checkForPerson function person people mongoose model Person Person
  • 流星内存不足

    我正在使用流星来制作报废引擎 我必须执行一个 HTTP GET 请求 这会向我发送一个 xml 但这个 xml 大于 400 ko 我得到一个异常 内存不足 result Meteor http get http SomeUrl com 致
  • 当存在打开的 ASP.NET 4.5 Websocket 时,IIS 应用程序池无法回收

    我遇到了一个问题 可以通过以下方式复制 您需要 IIS8 因此必须在 Windows 8 或 Windows Server 2012 R2 上 在 IIS 管理器中创建一个新网站 例如在端口 8881 上的 TestWs 指向一个新文件夹

随机推荐

  • 人工智能学习历程数学篇-概率论(1)

    人工智能学习历程数学篇 概率论 1 概率论基础 随机变量 概率论的一切定义的基础都来源于随机变量 那么何为随机变量呢 所谓的随机变量变量 X 并不代表一个具体的数字 而是一种概率分布 我们可以这样理解随机变量X 当你每次去看随机变量数据的具
  • java stringbuffer 赋值_Java常用类(String, StringBuffer, StringBuilder)

    一 String类 String的实例化方式 通过字面量定义的方式 String str hello world 通过new 构造器的方式 String str new String hello world 面试题 String s new
  • python读取excel某一区域单元格的内容

    sheet1 row values 0 6 10 取第1行 第6 10列 不含第10表 sheet1 col values 0 0 5 取第1列 第0 5行 不含第5行 sheet1 row slice 2 0 2 获取单元格值类型和内容
  • 【链表】循环链表知识点-内含代码基本操作及其说明

    目录 一 概念 二 循环链表基本操作 初始化 头插 插在最前面 尾插 查找数据 获取val的前驱 获得后继 删除数据 删除某位置的值 输出数据 判断plist是否为空链表 没有数据节点 获取plist长度 数据节点的个数 插入数据 获取pl
  • 最短路径算法 迪杰斯特拉、佛洛依德和贝尔曼

    最短路径算法 迪杰斯特拉算法 佛洛依德算法 迪杰斯特拉算法 迪杰斯特拉算法用来解决在有向有权图中某一个点到任意一点的最短路径问题 注意 只能用来解决权为非零的情况 不能够解决权为负数的情况 思想 我是一个搬运工 思想就不讲了 主要是代码 d
  • Vue基础入门---Vue-router

    简介 由于Vue在开发时对路由支持的不足 后来官方补充了vue router插件 它在Vue的生态环境中非常重要 在实际开发中只要编写一个页面就会操作vue router 要学习vue router就要先知道这里的路由是什么 这里的路由并不
  • vps用途

    VPS用途 1 虚拟主机空间 VPS主机非常适合为中小企业 小型门户网站 个人工作室 SOHO一族提供网站空间 较大独享资源 安全可靠的隔离保证了用户对于资源的使用和数据的安全 2 电子商务平台 VPS主机与独立服务器的运行完全相同 中小型
  • STL教程5-STL基本概念及String和vector使用

    活动地址 毕业季 进击的技术er 夏日炎炎 热浪中我们迎来毕业季 这是告别 也是迈向新起点的开始 CSDN诚邀各毕业生 在校生 职场人讲述自己的毕业季故事 分享自己的经验 技术er的进击之路 等你来书写 你可以选择适合自己的对应身份从以下相
  • Calendar根据当前(指定)日期取出指定时间

    以下为亲测 持续更新 一 Calendar根据当前 指定 日期取出本周一本周日和下周一下周日时间 根据Calendar java中定义的DAY OF WEEK来看 Field number for code get code and cod
  • 【LeetCode104】二叉树的最大深度(递归+迭代)

    题目描述 首刷自解 int maxDepth TreeNode root if root nullptr return 0 return max maxDepth root gt left maxDepth root gt right 1
  • k-means算法Python实现--机器学习ML

    k means algorithm 一些概念 partial clustering 每一簇的数据不重叠 至少一簇一个数据 hieraichical clustering 通过构建层次结构来确定聚类分配 density based clust
  • 设计模式-访问者模式

    1 访问者模式被称为最复杂的设计模式 访问者模式访问者模式 Visitor pattern 是一种将数据结构与数据操作分离的设计模式 是指封装一些作用于某种数据结构中的各元素的操作 它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
  • png透明通道分离

    关于photoshop中png打开问题 前面也说到过http blog csdn net shenmifangke article details 52638716 ps在打开png格式图片的时候 实际上是把透明通道应用到了所有通道上 这样
  • IndentationError: unindent does not match any outer indentation level

    IndentationError unindent does not match any outer indentation level 遇到这个错误 是因为新的Python语法中是不支持的代码对齐中 混用TAB和空格的 解决方法 使用工具
  • 【C语言】之实现闰年判断

    文件名 leapYear c 功能 任意输入一个年份 判断其是否为闰年 编辑人 王廷云 include
  • VB+SQL银行设备管理系统设计与实现

    摘要 随着银行卡的普及 很多地方安装了大量的存款机 取款机和POS机等银行自助设备 银行设备管理系统可以有效的记录银行设备的安装和使用情况 规范对自助设备的管理 从而为用户提供更加稳定和优质的服务 本文介绍了银行设备管理系统的设计和开发过程
  • ooad设计模型

    设计模式 Design pattern 是一套被反复使用 多数人知晓的 经过分类编目的 代码设计经验的总结 使用设计模式是为了可重用代码 让代码更容易被他人理解 保证代码可靠性 毫无疑问 设计模式于己于他人于系统都是多赢的 设计模式使代码编
  • 前端之vue3使用动画库animate.css(含动画、过渡)

    动画与过渡 一 动画效果 1 默认动画 实例 动画语法 2 给transition指定name 二 过渡效果 三 多个元素过渡 四 vue3使用动画库 动画库animate css 五 总结 一 动画效果 1 默认动画 实例
  • github怎么自动更新被人更新过的项目_新出炉的免费开源平台,GitHub官方出品

    软件名称 GitHub Desktop 2 2 4 安装环境 Windows 下载链接 下载链接 https www sssam com 10822 html 软件简介 GitHub是一个面向开源及私有软件项目的托管平台 因为只支持git
  • 前端实现websocket(vue3)

    在config index js文件中配置一下websocket websocket的域名和端口号的配置 const BASE URL localhost const WS PORT 8080 const WS ADDRESS ws BAS