Echarts+vue电商平台数据可视化——webSocket改造项目

websocket的基本使用,用于测试前端能否正常获取到后台数据

后台代码编写:

javascript 复制代码
const path = require("path");
const fileUtils = require("../utils/file_utils");
const WebSocket = require("ws");
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({
  port: 9998,
});
// 服务端开启了监听
// 导出一个函数listen
module.exports.listen = () => {
  // 对客户端的连接事件进行监听
  // client: 代表的是客户端的连接socket对象
  wss.on("connection", (client) => {
    console.log("有客户端连接成功了...");
    // 对客户端的连接对象进行message事件的监听
    // msg:由客户端发给服务器的数据
    client.on("message", async (msg) => {
      console.log("客户端发送数据给服务器:" + msg);
      let payload = JSON.parse(msg);
      const action = payload.action;
      if (action === "getData") {
        let filePath = "../data/" + payload.chartName + ".json";
        // payload.charName; // trend seller map rank hot stock
        filePath = path.join(__dirname, filePath);
        const ret = await fileUtils.getFileJsonData(filePath);
        // 需要再服务器获取到数据的基础上,增加一个data的字段
        // data对应的值,就是某个json文件的内容
        payload.data = ret;
        client.send(JSON.stringify(payload));
      } else {
        // 原封不动的将所有收到的数据转发给每一个处于连接状态的客户端
        // wss.clients //所有客户端的连接
        wss.clients.forEach((client) => {
          client.send(JSON.stringify(payload));
        });
      }
      // 由服务端往客户端发送数据
      // client.send("hello socket from backend");
    });
  });
};

调用的获取文件路径的方法(getFileJsonData):

javascript 复制代码
// 读取文件的工具方法
const fs = require("fs");
module.exports.getFileJsonData = (filePath) => {
  // 根据文件的路径,读取文件的内容
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, "utf-8", (error, data) => {
      if (error) {
        // 读取文件失败
        reject(error);
      } else {
        // 读取文件成功
        // return data; // 这里的return返回的是这个函数的调用者,而不是getFileJsonData这个函数的调用者
        // 读取文件是一个异步任务,对于一个异步任务,我们也不能通过return的方式来将数据返回给调用者
        resolve(data);
      }
    });
  });
};

前端使用:

javascript 复制代码
    <button id="connect">连接</button>
    <button id="send" disabled="true">发送数据</button>
    <br />从服务端接收的数据如下: <br />
    <span id="recv"></span>
    <script>
      var connect = document.querySelector("#connect");
      var send = document.querySelector("#send");
      var recv = document.querySelector("#recv");
      let ws = null;
      connect.onclick = function () {
        ws = new WebSocket("ws://localhost:9998");
        ws.onopen = () => {
          console.log("连接服务端成功了...");
          send.disabled = false;
        };
        ws.onclose = () => {
          console.log("连接服务器失败或关闭");
          send.disabled = true;
        };
        ws.onmessage = (msg) => {
          console.log("接收从服务器发送过来的数据了");
          console.log(msg);
          recv.innerHTML = msg.data;
        };
      };
      send.onclick = function () {
        ws.send(
          JSON.stringify({
            action: "getData",
            socketType: "trendData",
            chartName: "trend",
            value: "",
          })
        );
        ws.send(
          JSON.stringify({
            action: "fullScreen",
            socketType: "fullScreen",
            chartName: "trend",
            value: true | false,
          })
        );
        ws.send(
          JSON.stringify({
            action: "themeScreen",
            socketType: "themeScreen",
            chartName: "",
            value: "",
          })
        );
      };
    </script>

websocket用来改造电商平台项目思维导图:


坐标轴的方向是一个从左往右的方向,朝那个方向就选取x1,y1,x2,y2就选取那几个值

横向:0,0,1,0

竖向:0,0,0,1

报错信息:

js:31[Vue warn]:挂接钩子时出错:"InvalidStateError:在WebSocket上执行send失败:仍处于连接状态。"

代码中的注释解释:

// 有一种报错情况,在组件还没有进行连接成功之前,连接需要一点时间,这个组件就已经进行了加载,就会调用mounted当中指明的send的方法,而send方法是socket_service.js当中定义的一个方法,就会往ws来进行一个send方法的调用,而此时此刻,还没有连接成功

javascript 复制代码
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
// 引入字体的文件
import "./assets/font/iconfont.css";
// 引入全局的样式文件
import "./assets/css/global.less";
import axios from "axios";
import SocketService from "@/utils/socket_service";
// 对服务端的数据进行连接
// SocketService.Instance().connect(); //这样写会报错,报错说明是Instance是不需要就加上小括号的
// 有一种报错情况,在组件还没有进行连接成功之前,连接需要一点时间,这个组件就已经进行了加载,就会调用mounted当中指明的send的方法,而send方法是socket_service.js当中定义的一个方法,就会往ws来进行一个send方法的调用,而此时此刻,还没有连接成功
SocketService.Instance.connect();
// 其他的组件调用websocket的方式  this.$socket
Vue.prototype.$socket = SocketService.Instance;
// 请求的基准路径的配置
axios.defaults.baseURL = "http://127.0.0.1:8888/api/";
// 将axios挂载到Vue的原型对象上
// 在别的组件中 this.$http
Vue.prototype.$http = axios;

// 将全局的echarts对象挂载到Vue的原型对象中
// 别的组件中this.$echarts
Vue.prototype.$echarts = window.echarts;

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

解决方法,添加一个连接标识,判断websocket连接成功还是失败,true连接成功,false连接失败

项目改造后的后台编写:

javascript 复制代码
export default class SocketService {
  // 单例
  static instance = null;
  static get Instance() {
    if (!this.instance) {
      this.instance = new SocketService();
    }
    return this.instance;
  }

  // 和服务器连接的socket对象
  ws = null;

  // 怎么在得到数据之后,将每个图表数据传递给每个图表组件,让图表数据可以得到更新
  // 先将每一个图表组件的某一个方法先存储在我们当前的这个模块中,比如一个实例属性中,一旦得到有服务端给我们的数据之后,在调用我们之前所存储起来的那个方法,就可以将数据传递给每个图表组件
  // 存储回调函数
  callBackMapping = {};

  // 标识是否连接成功
  connected = false;
  // 记录重试的次数
  sendRetryCount = 0;
  // 重新连接尝试的次数
  connectRetryCount = 0;

  // 定义连接服务器的方法
  connect() {
    // 连接服务器
    if (!window.WebSocket) {
      return console.log("您的浏览器不支持WebSocket");
    }
    this.ws = new WebSocket("ws://localhost:9998");
    // 连接成功的事件
    this.ws.onopen = () => {
      console.log("连接服务器成功了");
      this.connected = true;
      // 重置重新连接的次数
      this.connectRetryCount = 0;
    };
    // 1.连接服务器失败
    // 2.当连接成功之后,服务器关闭的情况
    this.ws.onclose = () => {
      console.log("连接服务器失败");
      // 标识是否连接成功,没有连接成功
      this.connected = false;
      this.connectRetryCount++;
      // 这个时候应该进行重新连接的尝试,但是每一次连接失败,下一次的连接都是500毫秒 不太合适,因为尝试的越多,可能服务器已经坏了,或者已经关闭了,就没有必要那么频繁的次数来进行重新连接的尝试
      setTimeout(() => {
        this.connect();
      }, 500 * this.connectRetryCount);
    };
    this.ws.onmessage = (msg) => {
      console.log("从服务器获取了数据");
      // 真正服务端发送过来的原始数据时在msg中的data字段
      // 如果在的得到数据之后把数据传递给每个图表组件会好一些,因为只有图表组件需要数据
      console.log(msg.data, msg, "--\\\\");
      const recvData = JSON.parse(msg.data);
      const socketType = recvData.socketType;
      // 判断回调函数是否存在
      if (this.callBackMapping[socketType]) {
        const action = recvData.action;
        if (action === "getData") {
          const realData = JSON.parse(recvData.data);
          this.callBackMapping[socketType].call(this, realData);
        } else if (action === "fullScreen") {
          this.callBackMapping[socketType].call(this, recvData);
        } else if (action === "themeScreen") {
          this.callBackMapping[socketType].call(this, recvData);
        }
      }
    };
  }

  // 下面的这个三个方法需要通过组件来调用
  // 回调函数的注册
  // socketType  这个函数的唯一标识,callBack这个函数的回调函数
  registerCallBack(socketType, callBack) {
    this.callBackMapping[socketType] = callBack;
  }
  // 取消某一个回调函数
  // socketType 这个函数的唯一标识
  unRegisterCallBack(socketType) {
    this.callBackMapping[socketType] = null;
  }
  // 发送数据的方法
  send(data) {
    // 判断此时此刻有没有连接成功
    if (this.connected) {
      this.sendRetryCount = 0;
      this.ws.send(JSON.stringify(data));
    } else {
      this.sendRetryCount++;
      setTimeout(() => {
        this.send(data);
      }, this.sendRetryCount * 500);
    }
    // this.ws.send(JSON.stringify(data));
  }
}

新旧setOption是一个相互整合,相互覆盖的过程

相关推荐
纳尼亚awsl6 小时前
处理元素卡在视野边界,滚动到视野内
前端·javascript·vue.js
永远不会太晚6 小时前
JavaScript的diff库详解(示例:vue项目实现两段字符串比对标黄功能)
前端·javascript·vue.js
永远不会太晚10 小时前
前端vue+el-input实现输入框中文字高亮标红效果(学习自掘金博主文章)
前端·vue.js·学习
前端Mu偶人11 小时前
nodejs结合七牛云上传文件
前端·javascript·vue.js
KLW7511 小时前
vant 地址记录
前端·javascript·vue.js
Zuojiangtao12 小时前
从@vue/cli项目迁移到Rsbuild
vue.js·webpack
xybDIY13 小时前
【OceanBase】使用 Superset 连接 OceanBase 数据库并进行数据可视化分析
数据库·信息可视化·oceanbase
_xaboy14 小时前
开源表单设计器form-create-designer如何保存设计器的规则和回显
vue.js·低代码·开源·动态表单·formcreate·低代码表单
jedi-knight14 小时前
使用python和paraview将三维数据可视化的方法
开发语言·经验分享·笔记·python·学习·信息可视化
火云牌神15 小时前
基于OAuth2.0和JWT规范实现安全易用的用户认证
vue.js·安全·fastapi