echarts+vue2实战(二)

news2024/11/16 7:42:48

目录

一、WebSocket【双向通信】的使用

1.1、前端

1.2、后端

二、前端组件的合并与优化

三、全屏切换

3.1、单页面切换

3.2、同页面多端联动

四、主题切换

4.1、单页面切换

4.2、同页面多端联动

一、WebSocket【双向通信】的使用

1.1、前端

在utils文件夹里创建socket_service.js,并在main.js里进行挂载

(1)、定义类SocketService,并定义成单例设计模式;

(2)、定义连接服务器的方法connect,(前端项目不用下载,直接window.socket即可);

(3)、监听事件:onopen、onclose、onmessage;

(4)、存储回调函数;

(5)、接收数据的处理;

(6)、定义发送数据的方法;

(7)、挂载SocketService对象到vue的原型对象上;

import SocketService from '@/utils/socket_service'
// 对服务端进行websocket的连接
SocketService.Instance.connect()
// 通过this.$socket.xxx获取所有方法
Vue.prototype.$socket = SocketService.Instance
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
        }
        // 连接连接服务端失败
        this.ws.onclose = () => {
            console.log('连接服务端失败');
            this.connected = false
            this.connectRetryCount++
            setTimeout(() => {
                this.connect()
            }, this.connectRetryCount * 500)
        }
        // 得到服务端发送过来的数据
        this.ws.onmessage = msg => {
            console.log('从服务端获取到了数据', msg.data)
            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 === 'themeChange') {
                    this.callBackMapping[socketType].call(this, recvData);//主题切换
                }
            }
        }
    }
    // 回调函数的注册
    registerCallBack(socketType, callBack) {
        this.callBackMapping[socketType] = callBack
    }
    // 取消某一个回调函数
    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)
        }
    }
}

1.2、后端

在service文件夹里创建web_socket_service.js,在app.js里引入

const WebSocketService = require('./service/web_socket_service')
// 开启服务端的监听,监听客户端的连接
// 当某一个客户端连接成功后,就会对这个客户端进行message事件的监听
WebSocketService.listen()

(1)、安装包 npm i ws -S;

(2)、创建对象;

(3)、监听事件;

(4)、发送数据;

const path = require('path')
const fileUtils = require('../utils/file_utils')
const WebSocket = require('ws')
const { log } = require('console')
// 创建WebSocket服务端的对象, 绑定的端口号是9998
const wss = new WebSocket.Server({
    port: 9998
})
// 服务端开启了监听
module.exports.listen = () => {
    // 对客户端的连接事件进行监听
    // client:代表的是客户端的连接socket对象
    wss.on('connection', client => {
        // console.log('有客户端连接成功了...')
        // 对客户端的连接对象进行message事件的监听
        // msg: 由客户端发给服务端的数据
        client.on('message', async msg => {
            let payload = JSON.parse(msg)
            console.log(action, '客户端发送数据给服务端了: ' + msg)
            const action = payload.action
            if (action === 'getData') {
                let filePath = '../data/' + payload.chartName + '.json'
                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 => {
//如果数据被转成了Buffer对象,故使用msg.toString()将Buffer转换为字符串,前端用JSON.parse(xxx)解析字符串为JSON对象即可
                    client.send(msg.toString())
                })
            }
        })
    })
}
// 备注:前后端约定的字段
// let msg = {
//     "action": 'getData',//获取数据方法名
//     "socketType": "trendData",//前端响应函数的标识
//     "chartName": 'trend',
//     "value": '',
//     "data":'.json里的数据'
// }

二、前端组件的合并与优化

(1)、在组件创建完成后,进行回调函数的注册;在组件销毁时,进行回调函数的取消;

(2)、发送数据给服务器;

(3)、直接 getData(ret) 得到数据,不用再发请求了;

(4)、重发数据机制

让属性connected在onopen时设置为true,在onclose时设置为false,计算重发次数

(5)、断开重连机制

如果失败,则延时的时长随着尝试的次数而增加,如果成功,则将次数归0

以Trend.vue组件为例:

  created() {
    this.$socket.registerCallBack('trendData', this.getData);
  },
  destroyed() {
    this.$socket.unRegisterCallBack('trendData');
  },
  mounted() {
       ......
    // this.getData();
    this.$socket.send({
      action: "getData",
      socketType: "trendData",
      chartName: "trend",
      value: "",
    });//发送数据给服务器,告诉它,该组件需要数据
  },
  methods:{
    // 旧版本
    // async getData() {
    //   const { data: ret } = await this.$http.get("trend");
    //   this.allData = ret;
    //   this.updateChart();
    // },
    // websocket版本
    getData(ret) {
      this.allData = ret;
      this.updateChart();
    },
}

三、全屏切换

以"热销商品占比图表"为例:

(1)、定义全屏状态的数据、样式;

(2)、在点击指定组件的放大图标时传递自己的属性名,在方法里根据对应的属性值切换对应的样式和图标,并调用组件自己的screenAdapter()

(3)、联动效果:

发送全屏数据给服务器,服务器在收到这个数据时,会转发给每一个处于连接状态的客户端,前端在created()时注册回调、在destroyed()时取消回调、在recvData()里接收到数据进行属性值处理。

3.1、单页面切换

3.2、同页面多端联动

四、主题切换

4.1、单页面切换

(1)、自己在echarts的"主题编辑器"里选择要切换的主题.json文件;

(2)、点击切换按钮,修改vuex中的theme数据(通过mutations修改state里的数据);

(3)、在每个组件里监听theme的变化,用xx.dispose()销毁当前图表,再重新渲染(在registerTheme()和init()函数里改为变化的theme)

(4)、HTML样式随之改变:

utils文件夹的theme_utils.js内容

const theme = {
    chalk: {
        backgroundColor: '#161522',
        titleColor: '#fff',
        logoSrc: 'logo_dark.png',//左上角logo图标路径
        themeSrc: 'qiehuan_dark.png',//切换主题按钮的图片路径
        headerBorderSrc: 'header_border_dark.png'//页面顶部的边框图片
    },
    vintage: {
        backgroundColor: '#fff',
        titleColor: '#000',
        logoSrc: 'logo_light2.png',
        themeSrc: 'qiehuan_light.png',
        headerBorderSrc: 'header_border_light.png'
    }
}
export function getThemeValue(themeName) {
    return theme[themeName]
}

store文件夹里的index内容

state: {
    theme: 'chalk',
  },
mutations: {
    changeTheme(state) {
      if (state.theme == 'chalk') {
        state.theme = 'vintage'
      } else {
        state.theme = 'chalk'
      }
    },
  },

以Hot.vue组件为例:

<template>
  <div class="com-container">
    <div class="com-chart" ref="hot_ref"></div>
    <!-- 左右箭头 -->
    <span class="iconfont arr-left" @click="toLeft" :style="comStyle">&#xe6ef;</span>
    <span class="iconfont arr-right" @click="toRight" :style="comStyle">&#xe6ed;</span>
    <!-- 一级标题 -->
    <span class="cat-name" :style="comStyle">{{ catName }}系列</span>
  </div>
</template>
<script>
import * as ets from "echarts";
import { mapState } from "vuex";
import chalk from "../../../../public/static/theme/chalk.json"; //自己下载
import vintage from "../../../../public/static/theme/vintage.json"; //自己下载
import { getThemeValue } from "@/utils/theme_utils.js";
export default {
  data() {
    return {
      isStyle: chalk,
    };
  },
  computed: {
    ...mapState(["theme"]),
    comStyle() {
      return {
        fontSize: `${this.titleFontSize}px`,
        color: getThemeValue(this.theme).titleColor,//HTML字体颜色改变
      };
    },
  },
  watch: {
    theme() {
      if (this.theme == "chalk") {
        this.isStyle = chalk;
      } else {
        this.isStyle = vintage;
      }
      this.chartInstance.dispose(); //销毁当前图表
      // 重新初始化图表、完成屏幕适配、更新图表展示
      this.initChart();
      this.screenAdapter();
      this.updateChart();
    },
  },
  methods: {
    // 初始化echartsInstance对象
    initChart() {
      // ets.registerTheme("chalk", chalk);
      // this.chartInstance = ets.init(this.$refs.hot_ref, "chalk");
      ets.registerTheme("isStyle", this.isStyle);
      this.chartInstance = ets.init(this.$refs.hot_ref, "isStyle");
    },
  },
};
</script>

4.2、同页面多端联动

可参考全屏切换模块

echartsPage.vue页面(整合所有组件)代码:

<template>
  <div class="screen-container" :style="containStyle">
    <header class="screen-header">
      <div>
        <img :src="headerSrc" alt="" />
      </div>
      <span class="logo">
        <img :src="logoSrc" alt="" />
      </span>
      <span class="title">电商平台实时监控系统</span>
      <div class="title-right">
        <img :src="themeSrc" class="qiehuan" @click="handleChangeTheme" />
        <span class="datetime">2049-01-01 00:00:00</span>
      </div>
    </header>
    <div class="screen-body">
      <section class="screen-left">
        <div
          id="left-top"
          :class="[fullScreenStatus.trend ? 'fullscreen' : '']"
        >
          <!-- 销量趋势图表 -->
          <Trend ref="trend"></Trend>
          <div class="resize">
            <span
              @click="changeSize('trend')"
              :class="[
                'iconfont',
                fullScreenStatus.trend
                  ? 'icon-compress-alt'
                  : 'icon-expand-alt',
              ]"
            ></span>
          </div>
        </div>
        <div
          id="left-bottom"
          :class="[fullScreenStatus.seller ? 'fullscreen' : '']"
        >
          <!-- 商家销售金额图表 -->
          <Seller ref="seller"></Seller>
          <div class="resize">
            <span
              @click="changeSize('seller')"
              :class="[
                'iconfont',
                fullScreenStatus.seller
                  ? 'icon-compress-alt'
                  : 'icon-expand-alt',
              ]"
            ></span>
          </div>
        </div>
      </section>
      <section class="screen-middle">
        <div
          id="middle-top"
          :class="[fullScreenStatus.map ? 'fullscreen' : '']"
        >
          <!-- 商家分布图表 -->
          <Map ref="map"></Map>
          <div class="resize">
            <span
              @click="changeSize('map')"
              :class="[
                'iconfont',
                fullScreenStatus.map ? 'icon-compress-alt' : 'icon-expand-alt',
              ]"
            ></span>
          </div>
        </div>
        <div
          id="middle-bottom"
          :class="[fullScreenStatus.rank ? 'fullscreen' : '']"
        >
          <!-- 地区销量排行图表 -->
          <Rank ref="rank"></Rank>
          <div class="resize">
            <span
              @click="changeSize('rank')"
              :class="[
                'iconfont',
                fullScreenStatus.rank ? 'icon-compress-alt' : 'icon-expand-alt',
              ]"
            ></span>
          </div>
        </div>
      </section>
      <section class="screen-right">
        <div id="right-top" :class="[fullScreenStatus.hot ? 'fullscreen' : '']">
          <!-- 热销商品占比图表 -->
          <Hot ref="hot"></Hot>
          <div class="resize">
            <span
              @click="changeSize('hot')"
              :class="[
                'iconfont',
                fullScreenStatus.hot ? 'icon-compress-alt' : 'icon-expand-alt',
              ]"
            ></span>
          </div>
        </div>
        <div
          id="right-bottom"
          :class="[fullScreenStatus.stock ? 'fullscreen' : '']"
        >
          <!-- 库存销量分析图表 -->
          <Stock ref="stock"></Stock>
          <div class="resize">
            <span
              @click="changeSize('stock')"
              :class="[
                'iconfont',
                fullScreenStatus.stock
                  ? 'icon-compress-alt'
                  : 'icon-expand-alt',
              ]"
            ></span>
          </div>
        </div>
      </section>
    </div>
  </div>
</template>

<script>
import Hot from "./components/Hot.vue";
import Map from "./components/Map.vue";
import Rank from "./components/Rank.vue";
import Seller from "./components/Seller.vue";
import Stock from "./components/Stock.vue";
import Trend from "./components/Trend.vue";
import { mapState } from "vuex";
import { getThemeValue } from "@/utils/theme_utils.js";
export default {
  data() {
    return {
      // 定义每一个图表的全屏状态
      fullScreenStatus: {
        trend: false,
        seller: false,
        map: false,
        rank: false,
        hot: false,
        stock: false,
      },
    };
  },
  created() {
    this.$socket.registerCallBack("fullScreen", this.recvData);
    this.$socket.registerCallBack("themeChange", this.recvThemeChange);
  },
  destroyed() {
    this.$socket.unRegisterCallBack("fullScreen");
    this.$socket.unRegisterCallBack("themeChange");
  },
  components: {
    Hot,
    Map,
    Rank,
    Seller,
    Stock,
    Trend,
  },
  computed: {
    ...mapState(["theme"]),
    headerSrc() {
      return "/static/img/" + getThemeValue(this.theme).headerBorderSrc;
    },
    logoSrc() {
      return "/static/img/" + getThemeValue(this.theme).logoSrc;
    },
    themeSrc() {
      return "/static/img/" + getThemeValue(this.theme).themeSrc;
    },
    containStyle() {
      return {
        backgroundColor: getThemeValue(this.theme).backgroundColor,
        color: getThemeValue(this.theme).titleColor,
      };
    },
  },
  methods: {
    changeSize(chartName) {
      // 全屏切换单页面写法
      // 改变fullScreenStatus中组件对应的属性值
      // this.fullScreenStatus[chartName] = !this.fullScreenStatus[chartName];
      // 调用每个组件里的屏幕适配方法
      // this.$nextTick(() => {
      //   this.$refs[chartName].screenAdapter();
      // });
      // 同页面多端联动切换写法
      const targetValue = !this.fullScreenStatus[chartName];
      this.$socket.send({
        action: "fullScreen",
        socketType: "fullScreen",
        chartName: chartName,
        value: targetValue,
      });
    },
    // 处理接收到的全屏数据
    recvData(data) {
      const chartName = data.chartName;
      const targetValue = data.value;
      this.fullScreenStatus[chartName] = targetValue;
      this.$nextTick(() => {
        this.$refs[chartName].screenAdapter();
      });
    },
    handleChangeTheme() {
      // this.$store.commit("changeTheme"); //修改VueX里的数据
      this.$socket.send({
        action: "themeChange",
        socketType: "themeChange",
        chartName: "",
        value: "",
      });
    },
    recvThemeChange() {
      this.$store.commit("changeTheme");
    },
  },
};
</script>
<style lang="less" scoped>
// 全屏样式的定义
.fullscreen {
  position: fixed !important;
  top: 0 !important;
  left: 0 !important;
  width: 100% !important;
  height: 100% !important;
  margin: 0 !important;
  z-index: 100;
}
.screen-container {
  width: 100%;
  height: 100%;
  padding: 0 20px;
  background-color: #161522;
  color: #fff;
  box-sizing: border-box;
}
.screen-header {
  width: 100%;
  height: 64px;
  font-size: 20px;
  position: relative;
  > div {
    img {
      width: 100%;
    }
  }
  .title {
    position: absolute;
    left: 50%;
    top: 50%;
    font-size: 20px;
    transform: translate(-50%, -50%);
  }
  .title-right {
    display: flex;
    align-items: center;
    position: absolute;
    right: 0px;
    top: 50%;
    transform: translateY(-80%);
  }
  .qiehuan {
    width: 28px;
    height: 21px;
    cursor: pointer;
  }
  .datetime {
    font-size: 15px;
    margin-left: 10px;
  }
  .logo {
    position: absolute;
    left: 0px;
    top: 50%;
    transform: translateY(-80%);
    img {
      height: 35px;
      width: 128px;
    }
  }
}
.screen-body {
  width: 100%;
  height: 100%;
  display: flex;
  margin-top: 10px;
  .screen-left {
    height: 100%;
    width: 27.6%;
    #left-top {
      height: 53%;
      position: relative;
    }
    #left-bottom {
      height: 31%;
      margin-top: 25px;
      position: relative;
    }
  }
  .screen-middle {
    height: 100%;
    width: 41.5%;
    margin-left: 1.6%;
    margin-right: 1.6%;
    #middle-top {
      width: 100%;
      height: 56%;
      position: relative;
    }
    #middle-bottom {
      margin-top: 25px;
      width: 100%;
      height: 28%;
      position: relative;
    }
  }
  .screen-right {
    height: 100%;
    width: 27.6%;
    #right-top {
      height: 46%;
      position: relative;
    }
    #right-bottom {
      height: 38%;
      margin-top: 25px;
      position: relative;
    }
  }
}
.resize {
  position: absolute;
  right: 20px;
  top: 20px;
  cursor: pointer;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1860913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【漏洞复现】华测监测预警系统——SQL注入漏洞

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 华测监测预警系统2.2版本存在sql注入&#xff0c;UserEdit接口S…

用构造函数为对象的数据成员实现输入和输出时间

在C程序中&#xff0c;对象的初始化是一个不可缺少的重要问题。不应该让程序员在这个问题上花过多的精力&#xff0c;C在类的设计中提供了较好的处理方法。 为了解决这个问题&#xff0c;C提供了构造函数&#xff08;constructor&#xff09;来处理对象的初始化。构造函…

【前端】HTML+CSS复习记录【1】

文章目录 前言一、p、br&#xff08;段落、换行&#xff09;二、短语标签&#xff08;用来呈现为被强调的文本&#xff09;三、sub、sup&#xff08;下标、上标&#xff09;四、b&#xff08;加粗文本&#xff09;五、块级元素与行内元素六、元素嵌套七、html注释系列文章目录 …

axios全局封装AbortController取消重复请求

为什么&#xff1f; 问题&#xff1a;为什么axios要配置AbortController&#xff1f;防抖节流不行吗&#xff1f; 分析&#xff1a; 防抖节流本质上是用延时器来操作请求的。防抖是判断延时器是否存在&#xff0c;如果存在&#xff0c;清除延时器&#xff0c;重新开启一个延…

【JavaEE】浅谈线程(二)

线程 线程的常见属性 线程属性可以通过下面的表格查看。 •ID 是线程的唯⼀标识&#xff0c;不同线程不会重复 • 名称是各种调试⼯具⽤到&#xff08;如jconsoloe&#xff09; • 状态表示线程当前所处的⼀个情况&#xff0c;下⾯我们会进⼀步说明 • 优先级高的线程理论上来…

从公共仓库拉取推送的镜像并启动_将镜像内部目录挂载到外部目录使用_从镜像中复制文件到本机目录_从本机目录复制文件到镜像中---分布式云原生部署架构搭建010

然后我们再去找一个机器 docker ps docker rm -f 0ab docker images docker rmi guignginx 把这个机器的之前的这个镜像,在运行的 和 之前的都删除掉 然后我们去仓库中,拉取我们刚刚推送的 可以看到右边是命令 docker pull leifengyang/guignginx:v1.0 然后再来看总结命…

Unity踩坑记录

1. 如果同时在父物体和子物体上挂载BoxCollider&#xff0c;那么当使用&#xff1a; private void OnTriggerEnter2D(Collider2D collision){if (collision.CompareTag("CardGroup")){_intersectCardGroups.Add(collision.GetComponent<CardGroup>());}} 来判…

基于Java微信小程序民宿短租系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

精通pip:Python开发者的必备技能

目录 1. 安装 pip 2. 使用 pip 安装包 3. 卸载包 4. 更新包 5. 列出已安装的包 6. 搜索包 7. 使用 requirements.txt 文件安装多个包 8. 升级 pip 自身 9. 虚拟环境 10. 冻结依赖 11. 使用国内镜像源 12. 安装特定版本的包 13. 批量安装包 14. 显示帮助信息 15.…

常微分方程算法之编程示例三(预估-校正法)

目录 一、研究问题 二、C代码 三、计算结果 一、研究问题 本节我们采用预估校正法&#xff08;改进欧拉法&#xff09;求解算例。 预估-校正法的原理及推导请参考&#xff1a; 常微分方程算法之预估-校正法&#xff08;改进Euler法&#xff09;_、改进欧拉法-CSDN博客https…

东昂科技从创业板改道北交所:大客户依赖症明显,巨额分红又募投补流

《港湾商业观察》施子夫 黄懿 2024年6月24日&#xff0c;厦门东昂科技股份有限公司&#xff08;以下简称&#xff0c;东昂科技&#xff09;在北交所网站披露第二轮审核问询函的回复。自2024年1月IPO申请获北交所受理以来&#xff0c;东昂科技已经收到北交所下发的两轮审核问询…

探索SoMeLVLM:面向社交媒体处理的大型视觉语言模型

SoMeLVLM: A Large Vision Language Model for Social Media Processing 论文地址: https://arxiv.org/abs/2402.13022https://arxiv.org/abs/2402.13022发表在ACL 2024 1.概述 在线社交媒体平台涌现出海量的文本与视觉内容,深刻揭示了人们如何交流、互动以及自我表达。随着通…

动态规划数字三角形模型——AcWing 275. 传纸条

动态规划数字三角形模型 定义 动态规划数字三角形模型是在一个三角形的数阵中&#xff0c;通过一定规则找到从顶部到底部的最优路径或最优值。 运用情况 通常用于解决具有递推关系、需要在不同路径中做出选择以达到最优结果的问题。比如计算最短路径、最大和等。 计算其他…

研究上百个小时,高手总结了这份 DALL-E 3 人物连续性公式(下)

根据前两篇学习&#xff0c;如何创建人物连续性公式&#xff0c;或多或少都会联想到 Midjourney 里面的 Seed 值&#xff0c;是否能运用到 Dall e3 里面&#xff0c;那么今天这篇文章更新来了&#xff01;&#xff01; 继续感谢这位伟大的作者&#xff1a;AshutoshShrivastava…

五大基于Cesium的开源框架及其优劣势,一文导读。

2024-03-12 10:49贝格前端工场 OpenGL基础上有了webGL&#xff0c;webGL基础上有了Cesium&#xff0c;Cesium基础上有了N多开源框架&#xff0c;本文带大家看一下。 1. CesiumJS CesiumJS 是 Cesium 引擎的核心框架&#xff0c;提供了丰富的 API 和组件&#xff0c;用于构建…

基于Java微信小程序校园订餐系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

大模型训练十大戒律!!

1.切勿微调&#xff08;Thou Shalt Not Fine-Tune&#xff09;&#xff1a;尽量写prompt&#xff0c;利用大模型本身的能力zeroshot&#xff0c;必要时辅以少量样本&#xff08;few-shot examples&#xff09;或检索增强生成&#xff08;RAG&#xff09;。微调成本高、速度慢且…

如何在web页面下做自动化测试?

自动化测试是在软件开发中非常重要的一环&#xff0c;它可以提高测试效率并减少错误率。在web页面下进行自动化测试&#xff0c;可以帮助我们验证网页的功能和交互&#xff0c;并确保它们在不同浏览器和平台上的一致性。本文将从零开始&#xff0c;详细介绍如何在web页面下进行…

充电宝哪个牌子最好最耐用?耐用西圣、罗马仕、绿联充电宝实测

目前充电宝是我们出行必备的“能量伴侣”。然而&#xff0c;市面上充电宝品牌繁多&#xff0c;让人眼花缭乱&#xff0c;究竟哪个牌子最好最耐用呢&#xff1f;为了给大家找到答案&#xff0c;我们精心挑选了西圣、罗马仕和绿联这三个备受关注的品牌&#xff0c;并对它们的充电…

小米6款手机霸榜618 Top20,看安卓巨头如何撼动苹果地位

618购物节&#xff0c;作为中国电商领域的一大盛事&#xff0c;每年都会吸引无数消费者的眼球。在这场购物狂欢中&#xff0c;智能手机市场的竞争尤为激烈。 今年618&#xff0c;小米以6款手机上榜累计销量TOP20&#xff0c;超越了苹果的5款&#xff0c;成为上榜机型最多的品牌…