vue3项目页面实现echarts图表渐变色的动态配置

news2024/11/28 16:29:34

 完整代码可点击vue3项目页面实现echarts图表渐变色的动态配置-星林社区
https://www.jl1mall.com/forum/PostDetail?postId=202410151031000091552查看

一、背景

在开发可配置业务平台时,需要实现让用户对项目内echarts图表的动态配置,让用户脱离代码也能实现简单的图表样式配置。颜色作为图表样式的重要组成部分,其配置方式是项目要解决的重点问题。

二、难点整理

1.可以支持渐变的颜色选择器。

2.渐变色选择器取值结果与echarts图表配置要求的转换

3.图表配置资源存储与更新机制

4.渐变取色器位置配置导致取色器选中的色值发生变化触发事件change频繁被调用,引起最近选取颜色列表更新速率过快和图表刷新过快造成的资源浪费问题等。

三、解决方法

1.渐变取色器

因为开发时间问题,这里直接选用了TDesign的颜色选择器,具体可以参考TDesign官网

<div style="display: inline-block;vertical-align: middle;margin-right: 1rem;" >
    <t-color-picker
        v-model="lineColor"
        defaultValue="#409cff"
        :show-primary-color-preview="false"
         :recent-colors="recentcolorsList"
        @change="changeLineColorThrottle"
    />
</div>

2.渐变色值类型转换

tdesign取色器获取到的渐变色值为形如:linear-gradient(90deg,rgba(0, 0, 0, 1) 0%,rgb(73, 106, 220) 100%) 的css渐变色写法

echarts图表配置渐变色写法为:

"color":{
    "colorStops":[
        {"offset":0,"color":"#2378f7"},
        {"offset":0.5,"color":"#2378f7"},
        {"offset":1,"color":"#83bff6"}
    ],
    "x":0,
    "y":0,
    "x2":1,
    "y2":0.5,
    "type":"linear",
    "global":false
}

因此需要对两种类型进行转换。

1) rgb与hex色值表达转换
function hexToRgb(hex){
    let str = hex.replace("#", "");
          if (str.length % 3) {
            return "hex格式不正确!";
          }
          //获取截取的字符长度
          let count = str.length / 3;
          //根据字符串的长度判断是否需要 进行幂次方
          let power = 6 / str.length;
          let r = parseInt("0x" + str.substring(0 * count, 1 * count)) ** power;
          let g = parseInt("0x" + str.substring(1 * count, 2 * count)) ** power;
          let b = parseInt("0x" + str.substring(2 * count)) ** power;
 
          return `rgb(${r}, ${g}, ${b})`;
}
function rgbToHex(rgb){
    let arr = rgb
            .replace("rgb", "")
            .replace("(", "")
            .replace(")", "")
            .split(",");
          // 转十六进制
          let h = parseInt(arr[0]).toString(16);
          let e = parseInt(arr[1]).toString(16);
          let x = parseInt(arr[2]).toString(16);
          if(h.length<2){
            h = '0' + h 
          }
          if(e.length<2){
            e = '0' + e 
          }
          if(x.length<2){
            x = '0' + x 
          }
          return "#" + h + e + x;
}
2)角度与坐标参数x,x2,y,y2的转化

css中角度是指水平线和渐变线之间的角度,逆时针方向计算。换句话说,0deg 将创建一个从下到上的渐变,90deg 将创建一个从左到右的渐变。【注意很多浏览器(Chrome、Safari、firefox等)的使用了旧的标准,即 0deg 将创建一个从左到右的渐变,90deg 将创建一个从下到上的渐变。换算公式 90 - x = y 其中 x 为标准角度,y为非标准角度。】

linear-gradient() 函数会绘制出一系列与渐变线垂直的彩色线,每条线都匹配与渐变线相交点的颜色。这条渐变线由包含渐变图形的容器的中心点和一个角度来定义的。渐变线上的颜色值是由不同的点来定义,包括起始点、终点,以及两者之间的可选的中间点(中间点可以有多个)。起点是渐变线上代表起始颜色值的点。终点是渐变线上代表最终颜色值的点。这两个点都是由渐变线和从最近的顶点发出的垂直线之间的交叉点定义的。

echarts图表实际上是基于canvas画布展示的,因此需要将起点和终点转换在canvas坐标系中。

角度与坐标参数转化

css渐变角度与canvas坐标参数转换过程

需要注意的是,渐变线与矩形的交点可能落在水平线上,也可能落在垂直线上,所以需要分情况进行计算,实现代码如下:

function calculateGradientCoordinate(
    width,
    height,
    angle = 180,
  ) {
    if (angle >= 360) angle = angle - 360;
    if (angle < 0) angle = angle + 360;
    angle = Math.round(angle);
  
    // 当渐变轴垂直于矩形水平边上的两种结果
    if (angle === 0) {
      return {
        x0: Math.round(width / 2),
        y0: height,
        x1: Math.round(width / 2),
        y1: 0,
      };
    }
    if (angle === 180) {
      return {
        x0: Math.round(width / 2),
        y0: 0,
        x1: Math.round(width / 2),
        y1: height,
      };
    }
  
    // 当渐变轴垂直于矩形垂直边上的两种结果
    if (angle === 90) {
      return {
        x0: 0,
        y0: Math.round(height / 2),
        x1: width,
        y1: Math.round(height / 2),
      };
    }
    if (angle === 270) {
      return {
        x0: width,
        y0: Math.round(height / 2),
        x1: 0,
        y1: Math.round(height / 2),
      };
    }
  
    // 从矩形左下角至右上角的对角线的角度
    const alpha = Math.round(
      (Math.asin(width / Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))) *
        180) /
        Math.PI,
    );
  
    // 当渐变轴分别于矩形的两条对角线重合情况下的四种结果
    if (angle === alpha) {
      return {
        x0: 0,
        y0: height,
        x1: width,
        y1: 0,
      };
    }
    if (angle === 180 - alpha) {
      return {
        x0: 0,
        y0: 0,
        x1: width,
        y1: height,
      };
    }
    if (angle === 180 + alpha) {
      return {
        x0: width,
        y0: 0,
        x1: 0,
        y1: height,
      };
    }
    if (angle === 360 - alpha) {
      return {
        x0: width,
        y0: height,
        x1: 0,
        y1: 0,
      };
    }
  
    // 以矩形的中点为坐标原点,向上为Y轴正方向,向右为X轴正方向建立直角坐标系
    let x0 = 0,
      y0 = 0,
      x1 = 0,
      y1 = 0;
  
    // 当渐变轴与矩形的交点落在水平线上
    if (
      angle < alpha || // 处于第一象限
      (angle > 180 - alpha && angle < 180) || // 处于第二象限
      (angle > 180 && angle < 180 + alpha) || // 处于第三象限
      angle > 360 - alpha // 处于第四象限
    ) {
      // 将角度乘以(PI/180)即可转换为弧度
      const radian = (angle * Math.PI) / 180;
      // 当在第一或第四象限,y是height / 2,否则y是-height / 2
      const y = angle < alpha || angle > 360 - alpha ? height / 2 : -height / 2;
      const x = Math.tan(radian) * y;
      // 当在第一或第二象限,l是width / 2 - x,否则l是-width / 2 - x
      const l =
        angle < alpha || (angle > 180 - alpha && angle < 180)
          ? width / 2 - x
          : -width / 2 - x;
      const n = Math.pow(Math.sin(radian), 2) * l;
      x1 = x + n;
      y1 = y + n / Math.tan(radian);
      x0 = -x1;
      y0 = -y1;
    }
  
    // 当渐变轴与矩形的交点落在垂直线上
    if (
      (angle > alpha && angle < 90) || // 处于第一象限
      (angle > 90 && angle < 180 - alpha) || // 处于第二象限
      (angle > 180 + alpha && angle < 270) || // 处于第三象限
      (angle > 270 && angle < 360 - alpha) // 处于第四象限
    ) {
      // 将角度乘以(PI/180)即可转换为弧度
      const radian = ((90 - angle) * Math.PI) / 180;
      // 当在第一或第二象限,x是width / 2,否则x是-width / 2
      const x =
        (angle > alpha && angle < 90) || (angle > 90 && angle < 180 - alpha)
          ? width / 2
          : -width / 2;
      const y = Math.tan(radian) * x;
      // 当在第一或第四象限,l是height / 2 - y,否则l是-height / 2 - y
      const l =
        (angle > alpha && angle < 90) || (angle > 270 && angle < 360 - alpha)
          ? height / 2 - y
          : -height / 2 - y;
      const n = Math.pow(Math.sin(radian), 2) * l;
      x1 = x + n / Math.tan(radian);
      y1 = y + n;
      x0 = -x1;
      y0 = -y1;
    }
  
    // 坐标系更改为canvas标准,Y轴向下为正方向
    x0 = Math.round(x0 + width / 2);
    y0 = Math.round(height / 2 - y0);
    x1 = Math.round(x1 + width / 2);
    y1 = Math.round(height / 2 - y1);
    return { x0, y0, x1, y1 };
}

echarts坐标参数取值范围为0~1,在传参时可以直接将width和height设置为1。

坐标参数转换回角度时,需要注意角度所在象限区域进行分情况讨论。

x=0.5 y=0, x2=0.5, y2=1 从上到下 

x=1 y=0.5, x2=0.5, y2=0 从下到上 

x=0 y=0.5, x2=1, y2=0.5 从左到右 

x=1 y=0.5, x2=0, y2=0.5 从右到左

实现代码如下:

function getDeg(x1,y1,x2,y2){
    var x = Math.abs(x1 - x2);
	var y = Math.abs(y1 - y2);
	var tan = x / y;
	var radina = Math.atan(tan); //用反三角函数求弧度
	var deg = Math.floor(180 / (Math.PI / radina)) || 0; //将弧度转换成角度
	/**
	 * 根据目标点判断象限(注意是笛卡尔坐标)
	 * 一: +,+
	 * 二: -,+
	 * 三: -,+
	 * 一: +,-
	 */

	//  * 二、三象限要加 180°
	if (x2 < 0 && y2 >= 0) {
		deg = 180 + deg;
	}
	if (x2 < 0 && y2 < 0) {
		deg = 180 + deg;
	}

	// 一、二象限 === 0 就是 180°
	if (deg === 0) {
		if ((x2 >= 0 && y2 > 0) || (x2 <= 0 && y2 > 0)) {
			deg = 180 + deg;
		}
	}
    if ((x2 <= 0 && y2 > 0)) {
			deg = 180 + deg;
		}
    if ((x2 >= 0 && y2 > 0) ) {
			deg = - (180 + deg);
		}

	return deg;
}

此外还需要对色值RGB和HEX进行转换,代码如下:

function hexToRgb(hex){
    let str = hex.replace("#", "");
          if (str.length % 3) {
            return "hex格式不正确!";
          }
          //获取截取的字符长度
          let count = str.length / 3;
          //根据字符串的长度判断是否需要 进行幂次方
          let power = 6 / str.length;
          let r = parseInt("0x" + str.substring(0 * count, 1 * count)) ** power;
          let g = parseInt("0x" + str.substring(1 * count, 2 * count)) ** power;
          let b = parseInt("0x" + str.substring(2 * count)) ** power;
 
          return `rgb(${r}, ${g}, ${b})`;
}
function rgbToHex(rgb){
    let arr = rgb
            .replace("rgb", "")
            .replace("(", "")
            .replace(")", "")
            .split(",");
          // 转十六进制
          let h = parseInt(arr[0]).toString(16);
          let e = parseInt(arr[1]).toString(16);
          let x = parseInt(arr[2]).toString(16);
          if(h.length<2){
            h = '0' + h 
          }
          if(e.length<2){
            e = '0' + e 
          }
          if(x.length<2){
            x = '0' + x 
          }
          return "#" + h + e + x;
}

以上就是css线性渐变格式与echarts线性渐变格式最为关键的转换过程。

3.图表配置资源存储与更新机制

图表的整体配置资源项目通过store进行存储,在页面挂载时进行读取解析。因为onMounted生命周期内,chart配置数据可能还未存储至store中,在此阶段进行初始化可能造成属性值不存在等报错。由于配置组件在配置时已经记录配置值,如果对chartOption进行持续监听会造成冲突,导致取色器异常。因此需要设置flag值判断页面是否为初始化。初始化代码如下:

watch(()=>chartOption,()=>{
    //chartOption的反复修改和监听导致的冲突
    if(pageUpdateFlag.value){
        if('lineStyle' in chartOption.value['series'][0]){
            if('type' in chartOption.value['series'][0]['lineStyle'] ){
                lineType.value = chartOption.value['series'][0]['lineStyle']['type']
            }
            if('width' in chartOption.value['series'][0]['lineStyle'] ){
                lineWidth.value = chartOption.value['series'][0]['lineStyle']['width']
            }
            if('color' in chartOption.value['series'][0]['lineStyle'] ){
                let color = chartOption.value['series'][0]['lineStyle']['color']
                if(typeof color !== 'string' && 'type' in color){
                    let x = color.x
                    let y = color.y
                    let x1 = color.x2
                    let y1 = color.y2
                    let deg = 90
                    deg = getDeg(x-0.5,y-0.5,x1-0.5,y1-0.5)
                    let colorStr = ''
                    //渐变颜色选择器里的color要用rgb形式
                    for(let i =0 ; i < color.colorStops.length;i++){
                        let curColor = color.colorStops[i].color
                        if( color.colorStops[i].color[0] == '#'){
                            curColor = hexToRgb(color.colorStops[i].color[0])
                        }
                        colorStr = colorStr + ',' + color.colorStops[i].color + ' ' + color.colorStops[i].offset*100 + '%'
                    }
                    let str = "linear-gradient("+deg+'deg'+colorStr+')'
                    lineColor.value = str

                }else{
                    lineColor.value = color
                }
            }
        }
        if('showBackground' in chartOption.value['series'][0]){
            isArea.value = true
            if('color' in chartOption.value['series'][0]['areaStyle']){
                let color = chartOption.value['series'][0]['areaStyle']['color']
                if(typeof color !== 'string' && 'type' in color){
                    let x = color.x
                    let y = color.y
                    let x1 = color.x2
                    let y1 = color.y2
                    let deg = 90
                    deg = getDeg(x-0.5,y-0.5,x1-0.5,y1-0.5)
                    let colorStr = ''
                    //渐变颜色选择器里的color要用rgb形式
                    for(let i =0 ; i < color.colorStops.length;i++){
                        let curColor = color.colorStops[i].color
                        if( color.colorStops[i].color[0] == '#'){
                            curColor = hexToRgb(color.colorStops[i].color[0])
                        }
                        colorStr = colorStr + ',' + color.colorStops[i].color + ' ' + color.colorStops[i].offset*100 + '%'
                    }
                    let str = "linear-gradient("+deg+'deg'+colorStr+')'
                    areaColor.value = str
                }else{
                    areaColor.value = color
                }
            }
        }else {
            isArea.value = false
        }
        pageUpdateFlag.value = false
    } 
},{deep:true})

获取到取色值时,需要对chart配置数据更新,并发送图表配置修改信号,让更新数据同步渲染至图表中。

    let curColor = value
    if(curColor.includes('linear')){
        //渐变色,需要解析转换
        let colorObj = parseLinearColor(curColor)
        chartOption.value['series'][0]['areaStyle']['color'] = deepcopy(colorObj)
    }else{
        chartOption.value['series'][0]['areaStyle']['color'] = curColor
    }
    store.changeChartIsChange(true,"option")
4.利用节流函数解决change事件频繁调用导致的一系列冲突问题

在使用TDesign取色器时,通过滑动条调整渐变色偏移量会导致change事件频繁调用,如果直接在change函数中获取value添加到最近使用颜色列表就会造成最近使用列表颜色刷新过快,近似值添加过多的问题。因此需要使用节流函数来避免这一问题。同时change的频繁调用也会导致图表数据更新过快,造成资源浪费等问题。因此本项目使用了节流函数对change的整体事件进行了处理。

节流函数:

import { ref } from 'vue';

export default function useThrottle(fn, delay) {
  const canRun = ref(true);
  return (...args) => {
    if (!canRun.value) return;
    canRun.value = false;
    setTimeout(() => {
      fn(...args);
      canRun.value = true;
    }, delay);
  };
};

取色器change事件:

const changeLineColorThrottle = useThrottle(changeLineColor,400)
function changeLineColor(value,context){
    addRecentColor(recentcolorsList,value)
    //不能直接value及其值进行任何
    //判断取色为纯色还是渐变,注意value为rgb(115, 171, 230)或linear-gradient(90deg,rgb(241, 29, 0) 0%,rgb(73, 106, 220) 100%)
    console.log('判断取色为纯色还是渐变',value,lineColor.value,lineColor.value.includes('linear'));
    let curColor = value
    if(curColor.includes('linear')){
        //渐变色,需要解析转换
        let colorObj = parseLinearColor(curColor)
        chartOption.value['series'][0]['lineStyle']['color'] = deepcopy(colorObj)
    }else{
        chartOption.value['series'][0]['lineStyle']['color'] = curColor
    }
    //!!注意:频繁设置状态可能紊乱,导致渐变取色器为黑色
    store.changeChartIsChange(true,"option")
}

添加最近使用颜色函数和格式转换函数:

function addRecentColor(recentcolorsList,color){
    //添加前应判断数组内是否有重复的色值,有则删除原色值
    for(let i =0 ; i < recentcolorsList.value.length; i++){
        if(recentcolorsList.value[i] == color){
            recentcolorsList.value.splice(i,1)
        }
    }
    recentcolorsList.value.unshift(color)
}
function parseLinearColor(curColor){
    //滑动取色时会造成颜色添加频繁
    let colorObj = {
            "colorStops": [],
            "x":0,
            "y":0,
            "x1":0,
            "y1":0,
            "type":"linear",
            "global":false
        }
        let deg = curColor.split('linear-gradient(')[1].split('deg')[0]
        let colorList = curColor.split('deg')[1].split(',r')
        for(let i = 1; i < colorList.length; i++ ){
            let arr = colorList[i].split(") ")
            let color = 'r'+arr[0]+')'
            if(color.includes('rgba')){
                color = color.replace('rgba','rgb')
            }
            color = rgbToHex(color)
            let offset = arr[1].split("%")[0]/100
            colorObj.colorStops.push({"offset":offset,"color":color})
        }
        let {x0,y0,x1,y1} = calculateGradientCoordinate(1,1,deg)
        colorObj.x = x0
        colorObj.x2 = x1
        colorObj.y = y0
        colorObj.y2 = y1
        console.log(deg,x0,y0,x1,y1,"deg转化x0,y0,x1,y1");
        return colorObj
}

以上就是实现echarts图表渐变色的动态配置的关键步骤。

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

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

相关文章

基于Matlab 人脸识别技术

Matlab 人脸识别技术 算法流程&#xff1a; 本系统运用PCA算法来实现人脸特征提取&#xff0c;然后通过计算欧式距离来判别待识别测试人脸&#xff0c;本个系统框架图如下&#xff1a; 图&#xff1a; 人脸识别系统框架图 整个系统的流程是这样的&#xff0c;首先通过图像采…

给哔哩哔哩bilibili电脑版做个手机遥控器

前言 bilibili电脑版可以在电脑屏幕上观看bilibili视频。然而&#xff0c;电脑版的bilibili不能通过手机控制视频翻页和调节音量&#xff0c;这意味着观看视频时需要一直坐在电脑旁边。那么&#xff0c;有没有办法制作一个手机遥控器来控制bilibili电脑版呢&#xff1f; 首先…

基于SpringBoot+Vue+uniapp的时间管理小程序的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

【文件加密系统】华企盾DSC服务程序启动失败解决办法

问题原因&#xff1a; 1.sa账户密码错误导致连接数据数据库失败无法启动DSC服务 解决方法&#xff1a; 用windows身份验证进入数据库更改sa用户密码&#xff1a;安全性>登录名>sa>右键属性>更改密码 ※如果显示请输入秘钥更改&#xff0c;使用更改完密码的sa账户登…

从0开始深度学习(16)——暂退法(Dropout)

上一章的过拟合是由于数据不足导致的&#xff0c;但如果我们有比特征多得多的样本&#xff0c;深度神经网络也有可能过拟合 1 扰动的稳健性 经典泛化理论认为&#xff0c;为了缩小训练和测试性能之间的差距&#xff0c;应该以简单的模型为目标&#xff0c;即模型以较小的维度的…

机器学习与神经网络:科技的星辰大海

前提 近日&#xff0c;2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者&#xff0c;这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家&#xff0c;如今却将全球范围内对机器学习和神经网络的研究和开发作为了一…

RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器

RSocket vs WebSocket&#xff1a;Spring Boot 3.3 中的两大实时通信利器 随着现代互联网应用的不断发展&#xff0c;实时通信已经成为许多应用程序不可或缺的功能。无论是社交网络、在线游戏还是数据监控系统&#xff0c;实时通信都能提供快速、无缝的信息交换。而实现实时通…

“主升筹码”,底部建仓信号+主升加仓位置,不错过任何行情

使用技巧 指标分为主图和副图 其中&#xff0c;主图主升筹码信号较多&#xff0c;副图的信号较少。这里&#xff0c;我说一个选股思路&#xff0c;就是底部主升筹码共振进场&#xff0c;上升过程中主图信号当作加仓信号。 选股&#xff0c;提供一个主升筹码共振选股&#xff0…

Redis 5.0 安装配置(Windows)

Redis 5.0之后支持Redis Stream等功能 下载地址&#xff1a;Releases tporadowski/redis GitHub 点击运行redis-server.exe 此外&#xff1a;Redis 6.0及以后版本目前都没有Windows版

【越狱插件】内网穿透 frpc、frps插件

内网穿透、frp、frpc、frps https://zhaoboy9692.github.io/repo 越狱源 https://zhaoboy9692.github.io/repo 苦于在ios越狱下没有frp穿透使用 特地开发了的越狱插件 基于最新frp0.48编译 ios14.6测试没问题 有问题及时反馈

ubuntu中使用cmake编译报错No CMAKE_CXX_COMPILER could be found.的解决方法

ubuntu中使用cmake编译报错No CMAKE_CXX_COMPILER could be found.的解决方法 No CMAKE_CXX_COMPILER could be found.Could NOT find CUDA (missing: CUDA_NVCC_EXECUTABLE CUDA_CUDART_LIBRARY)Could not find a package configuration file provided by "OpenCV" …

【SQL|大数据|数据清洗|过滤】where条件中 “ != “ 和 “ NOT IN() ” 对NULL的处理

对数据进行清洗过滤的时候&#xff0c;NULL往往是一个很特殊的存在&#xff0c;对NULL值的存在通常有以下三种方式 1、保留NULL 2、过滤掉NULL 3、将NULL替换为其他符合业务需求的默认常量 下面是一些常用处理NULL的方式&#xff1a; 如下图所示数据源&#xff1a; car_vin&…

android openGL ES详解——缓冲区VBO/VAO/EBO/FBO

目录 一、缓冲区对象概念 二、分类 三、顶点缓冲区对象VBO 1、概念 2、为什么使用VBO 3、如何使用VBO 生成缓冲区对象 绑定缓冲区对象 输入缓冲区数据 更新缓冲区中的数据 删除缓冲区 4、VBO应用 四、顶点数组对象VAO 1、概念 2、为什么使用VAO 3、如何使用VAO…

ai修复照片工具哪个好?在线将模糊图像变清晰就用它

最近想尝试学习一下复古照片的拍摄风格&#xff0c;一波翻箱倒柜的操作翻出了以前家里拍的照片&#xff0c;却发现有些照片出现了氧化褪色&#xff0c;看不清原本图像的情况。 想看清晰一点的照片却找不到原本的底片&#xff0c;没办法再次冲洗新的相纸出来&#xff0c;该怎么…

Generative AI project lifecycle 生成式人工智能项目的全生命周期

这篇文章&#xff0c;你将学习到开发和部署一个由LLM驱动的应用程序所需的技术。在你将了解一个生成式AI项目的全生命周期&#xff0c;这可以帮助指导你完成这项工作。这个框架映射出了从概念到发布所需的任务。这里有一个整体生命周期的图表。我们将逐个阶段地讨论它。 在任何…

一文说明MySQL索引

最近研究了一下关于MySQL索引方面的面试题&#xff0c;以及可能拓展的问题&#xff0c;与大家分享 索引 在MySQL中&#xff0c;常见的索引类型包括以下几种&#xff1a; 普通索引&#xff08;INDEX&#xff09; &#xff1a;这是最基本的索引类型&#xff0c;可以包含一个或多…

基于springboot+vue实现的助学兼职系统(源码+L文+ppt)4-092

基于springbootvue实现的助学兼职系统&#xff08;源码L文ppt&#xff09;4-092 第4章 系统设计 4.1 总体功能设计 一般学生、招聘公司和管理者都需要登录才能进入助学兼职系统&#xff0c;使用者登录时会在后台判断使用的权限类型&#xff0c;包括一般使用者和管理者,一般使…

探索 Python 中的 XML 转换利器:xml2dict

文章目录 **探索 Python 中的 XML 转换利器&#xff1a;xml2dict**一、背景介绍二、xml2dict 是什么&#xff1f;三、如何安装 xml2dict&#xff1f;四、基本用法五、实际应用场景六、常见问题及解决方案七、总结 探索 Python 中的 XML 转换利器&#xff1a;xml2dict 一、背景…

构建智能暖箱监控系统:基于C#和WPF的完整指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

鸿蒙前端-1. 层叠效果

代码Stack&#xff08;{alignContent&#xff1a;Alignment.Center}&#xff09;{ Item1&#xff08;&#xff09; Item2&#xff08;&#xff09; Item3&#xff08;&#xff09;} 默认是居中对齐&#xff0c;后面的Item的优先级比前面的要高。 特点&#xff1a;代码简洁&…