vue使用WebSocket模拟实现聊天功能

下面是详细讲解“vue使用WebSocket模拟实现聊天功能”的攻略。

一、背景介绍

WebSocket协议是HTML5出现后新增的一项协议,基于TCP协议,可以实现客户端和服务器的双向通信。相比传统的Ajax轮询或Comet长轮询方式,WebSocket具有更低的延迟、更高的性能和更强的兼容性。

在Vue中使用WebSocket可以实现实时更新数据、聊天功能等。下面讲解如何使用WebSocket模拟实现前端聊天功能。

二、使用WebSocket模拟实现简单聊天功能

1.创建WebSocket

在Vue组件中,使用WebSockets来建立与服务器之间的连接。可以在组件的created或mounted钩子函数中创建WebSocket实例:

mounted() {
  const ws = new WebSocket('ws://localhost:3000');
  ws.onmessage = this.handleMessage;
  this.ws = ws;
},

2.发送消息

WebSocket中发送消息是使用send()方法,我们可以在组件方法中发送消息:

handleSend() {
  const message = this.message;
  this.ws.send(message);
}

3.接收消息

WebSocket的接收消息是使用onmessage事件,在组件中定义事件处理函数:

handleMessage(event) {
  const data = event.data;
  console.log(data);
  this.messageList.push(data);
}

4.显示聊天记录

将聊天记录渲染到页面上,可以使用v-for指令遍历消息列表:

<div v-for="message in messageList" :key="message">{{ message }}</div>

5.完整代码

下面是一个简单的聊天组件的完整代码示例:

<template>
  <div>
    <div v-for="message in messageList" :key="message">{{ message }}</div>
    <input type="text" v-model="message" />
    <button @click="handleSend">发送</button>
  </div>
</template>

<script>
export default {
  name: "Chat",
  data() {
    return {
      message: "",
      messageList: [],
      ws: null
    };
  },
  mounted() {
    const ws = new WebSocket("ws://localhost:3000");
    ws.onmessage = this.handleMessage;
    this.ws = ws;
  },
  methods: {
    handleSend() {
      const message = this.message;
      this.ws.send(message);
    },
    handleMessage(event) {
      const data = event.data;
      console.log(data);
      this.messageList.push(data);
    }
  }
};
</script>

三、使用WebSocket模拟实现高级聊天功能

除了简单的实时聊天,我们可以使用WebSocket模拟实现更复杂的功能,例如“在线用户列表”、“发送图片”等。

1.监听WebSocket连接

在服务器端,需要监听WebSocket连接,当有新的WebSocket连接时,保存该连接的WebScoket实例,便于后续操作。

const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 3000 });

const users = new Map();

wss.on("connection", function connection(ws) {
  ws.on("message", function incoming(message) {
    handleMessage(ws, message);
  });

  ws.on("close", function() {
    handleDisconnect(ws);
  });

  ws.on("error", function(e) {
    console.log(e);
  });
});

function handleMessage(ws, message) {
  const data = JSON.parse(message);
  const action = data.action;

  switch (action) {
    case "LOGIN":
      handleLogin(ws, data);
      break;
    case "LOGOUT":
      handleLogout(ws);
      break;
    case "MESSAGE":
      handleMessageSend(ws, data);
      break;
    case "IMAGE":
      handleImageSend(ws, data);
      break;
    default:
      break;
  }
}

function handleLogin(ws, data) {
  const { userId } = data;
  users.set(userId, ws);
  broadcast(ws, {
    type: "USER_LIST",
    data: Array.from(users.keys())
  });
}

function handleLogout(ws) {
  const user = [...users].find(([key, value]) => value === ws);
  if (user) {
    users.delete(user[0]);
    broadcast(ws, {
      type: "USER_LIST",
      data: Array.from(users.keys())
    });
  }
  console.log("disconnect");
}

function handleMessageSend(ws, data) {
  const { userId, message } = data;
  const targetWs = users.get(userId);
  if (targetWs) {
    targetWs.send(
      JSON.stringify({
        type: "MESSAGE",
        data: {
          userId: userId,
          message: message
        }
      })
    );
  }
}

function handleImageSend(ws, data) {
  const { userId, imageUrl } = data;
  const targetWs = users.get(userId);
  if (targetWs) {
    targetWs.send(
      JSON.stringify({
        type: "IMAGE",
        data: {
          userId: userId,
          imageUrl: imageUrl
        }
      })
    );
  }
}

function handleDisconnect(ws) {
  const user = [...users].find(([key, value]) => value === ws);
  if (user) {
    users.delete(user[0]);
    broadcast(ws, {
      type: "USER_LIST",
      data: Array.from(users.keys())
    });
  }
}

function broadcast(ws, data) {
  wss.clients.forEach(function each(client) {
    if (client !== ws && client.readyState === WebSocket.OPEN) {
      client.send(JSON.stringify(data));
    }
  });
}

2.服务端处理消息

在服务端,使用WebSocket实现的聊天功能,需要根据业务需求包装不同的消息格式。例如,发送消息时包装成:

{
  type: 'MESSAGE',
  data: {
    userId: 'xxx',
    message: 'test message'
  }
}

发送图片时包装成:

{
  type: 'IMAGE',
  data: {
    userId: 'xxx',
    imageUrl: 'http://xxx.jpg'
  }
}

3.监听WebSocket事件

在Vue中,可以监听WebSocket的onopenonerroroncloseonmessage等事件。例如,在组件mounted钩子中监听WebSocket的连接和消息:

mounted() {
  const ws = new WebSocket("ws://localhost:3000");
  ws.onopen = this.handleOpen;
  ws.onerror = this.handleError;
  ws.onclose = this.handleClose;
  ws.onmessage = this.handleMessage;
  this.ws = ws;
},

4.发送和接收消息

发送和接收消息的示例代码如下所示:

handleSend() {
  const message = {
    action: "MESSAGE",
    userId: this.userId,
    message: this.message
  };
  this.ws.send(JSON.stringify(message));
  this.message = "";
},
handleImageSend(event) {
  const file = event.target.files[0];
  const formData = new FormData();
  formData.append("image", file);
  const message = {
    action: "IMAGE",
    userId: this.userId
  };
  this.uploadImage(formData, message);
},
handleMessage(event) {
  const data = JSON.parse(event.data);
  const type = data.type;
  const messageType = {
    MESSAGE: "message",
    IMAGE: "image",
    USER_LIST: "userList"
  }[type];
  const messageData = data.data;
  const userId = messageData.userId;
  const messageContent = messageData.message || messageData.imageUrl;
  this.messageList.push({
    type: messageType,
    userId: userId,
    content: messageContent
  });
}

5.完整代码

下面是实现完整功能的Vue组件的代码示例:

<template>
  <div>
    <div class="user-list">
      <div v-for="userId in userList" :key="userId">{{ userId }}</div>
    </div>
    <div class="chat-log">
      <div class="message" v-for="message in messageList" :key="message.id">
        <div v-if="message.type === 'message'">{{ message.userId }}:{{ message.content }}</div>
        <div v-if="message.type === 'image'"><img :src="message.content" /></div>
      </div>
    </div>
    <div class="chat-input">
      <input type="text" v-model="message">
      <button @click="handleSend">发送</button>
      <input type="file" accept="image/*" @change="handleImageSend" />
    </div>
  </div>
</template>

<script>
export default {
  name: "Chat",
  data() {
    return {
      userId: "user1",
      message: "",
      messageList: [],
      ws: null,
      userList: []
    };
  },
  mounted() {
    const ws = new WebSocket("ws://localhost:3000");
    ws.onopen = this.handleOpen;
    ws.onerror = this.handleError;
    ws.onclose = this.handleClose;
    ws.onmessage = this.handleMessage;
    this.ws = ws;
  },
  methods: {
    handleClose() {
      console.log("close");
    },
    handleError(event) {
      console.log(event);
    },
    handleOpen() {
      console.log("open");
      const message = {
        action: "LOGIN",
        userId: this.userId
      };
      this.ws.send(JSON.stringify(message));
    },
    handleSend() {
      const message = {
        action: "MESSAGE",
        userId: this.userId,
        message: this.message
      };
      this.ws.send(JSON.stringify(message));
      this.message = "";
    },
    handleImageSend(event) {
      const file = event.target.files[0];
      const formData = new FormData();
      formData.append("image", file);
      const message = {
        action: "IMAGE",
        userId: this.userId
      };
      this.uploadImage(formData, message);
    },
    handleMessage(event) {
      const data = JSON.parse(event.data);
      const type = data.type;
      const messageType = {
        MESSAGE: "message",
        IMAGE: "image",
        USER_LIST: "userList"
      }[type];
      const messageData = data.data;
      const userId = messageData.userId;
      const messageContent = messageData.message || messageData.imageUrl;
      this.messageList.push({
        type: messageType,
        userId: userId,
        content: messageContent
      });
      if (type === "USER_LIST") {
        this.userList = messageData;
      }
    },
    uploadImage(formData, message) {
      axios
        .post("http://localhost:3000/upload", formData, {
          headers: {
            "Content-Type": "multipart/form-data"
          }
        })
        .then(response => {
          message.imageUrl = response.data.url;
          this.ws.send(JSON.stringify(message));
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
};
</script>

<style>
.user-list {
  display: flex;
  flex-direction: column;
  width: 100px;
}
.chat-log {
  height: 300px;
}
.chat-log .message {
  display: flex;
}
.chat-log .message img {
  max-width: 100px;
  max-height: 100px;
}
.chat-input {
  display: flex;
  flex-direction: column;
}
</style>

以上就是使用WebSocket模拟实现聊天功能的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue使用WebSocket模拟实现聊天功能 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • 浅谈flask源码之请求过程

    关于“浅谈flask源码之请求过程”的攻略,我可以提供以下详尽的说明。 标题 首先,需要标明本文的标题。我们可以使用一级标题来表示本文主要讲述的内容,如下所示: 浅谈Flask源码之请求过程 简介 接下来,我们需要提供一些基本的介绍,而这部分可以使用二级标题来表示。 Flask是一款轻量级Web框架,其核心思想是保持简单,而它的代码也相对精简,易于阅读和学习…

    Flask 2023年5月15日
    00
  • python jinja2模板的使用示例

    下面我将详细讲解“python jinja2模板的使用示例”的完整攻略,包含两个示例。 1. 安装Jinja2 首先,你需要安装Jinja2。如果你使用的是Python3,可以通过如下命令进行安装: pip3 install jinja2 2. 示例一 假如你有这样一个 hello.html 的模板文件: <html> <head> …

    Flask 2023年5月15日
    00
  • 手把手教你利用Python创建一个游戏窗口

    我很乐意为你讲解如何利用Python创建一个游戏窗口的完整攻略。请注意,为了让回答更加易于阅读,下文将使用标题、代码块等Markdown格式进行排版。 准备工作 在创建游戏窗口之前,我们需要安装pygame库,该库可以帮助我们方便地创建游戏窗口。你可以使用以下命令在终端中安装该库: pip install pygame 安装完成后,我们可以开始创建游戏窗口了…

    Flask 2023年5月16日
    00
  • Flask 的路由Route详情

    下面是关于 Flask 的路由 Route 的详细攻略。 什么是路由Route 路由 Route 是指在 web 应用中指定 URL 和对该 URL 请求的响应方式的方式。在 Flask 中,路由 Route 可以使用 @app.route() 装饰器来实现。 Flask 路由Route的语法 Flask 中使用 @app.route() 装饰器来指定 UR…

    Flask 2023年5月15日
    00
  • Python的Flask框架中SQLAlchemy使用时的乱码问题解决

    首先我先介绍一下Flask框架和SQLAlchemy。 Flask是一个轻量级的Web应用框架,它使用Python语言编写,能够快速开发实现功能简单的Web应用程序。SQLAlchemy则是Python下的一款ORM框架,通过SQLAlchemy,我们不再需要自己写SQL语句来操作数据库,而只需要使用Python语言对ORM框架提供的库函数进行操作即可。 在…

    Flask 2023年5月16日
    00
  • Windows系统下使用flup搭建Nginx和Python环境的方法

    下面是完整的攻略。首先,需要安装flup和Nginx,然后配置Nginx并使用flup搭建Python环境。 安装flup和Nginx 安装flup: $ pip install flup 安装Nginx: $ sudo apt-get update $ sudo apt-get install nginx 配置Nginx 配置Nginx以监听80端口,以便…

    Flask 2023年5月16日
    00
  • Django开发RESTful API实现增删改查(入门级)

    下面我详细介绍一下“Django开发RESTful API实现增删改查(入门级)”的完整攻略及两个示例: 一、开发环境准备 1. 安装 Python 和 Django 首先,需要安装 Python 和 Django。Python 是一门编程语言,而 Django 是 Python 的一个 Web 框架。我们使用 Django 来开发 Web 应用程序。可以通…

    Flask 2023年5月16日
    00
  • flask/django 动态查询表结构相同表名不同数据的Model实现方法

    Flask/Django是目前非常流行的Python Web框架,可以用于开发各种规模的Web应用程序。在开发Web应用程序时,经常需要动态地查询不同数据表中结构相同的数据。本文将介绍如何实现动态查询表结构相同、表名不同的数据表。 方法一:使用Django的多数据库 在Django应用程序中,可以使用多个数据库连接(Multi-database)来连接多个数…

    Flask 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部