当前位置: 首页 > article >正文

封装渐变堆叠柱状图组件附完整代码

在这里插入图片描述

组件功能

这是一个渐变堆叠柱状图组件,主要功能包括:

  1. 在一根柱子上同时显示高、中、低三种危险级别数据
  2. 使用渐变色区分不同危险级别(高危红色、中危橙色、低危蓝色)
  3. 悬停显示详细数据信息(包括总量和各级别数据)
  4. 自适应容器大小变化

使用方法在父组件中引入组件并传入数据

<template><JianbianZhu :warningData="warningData" :warningSevenItem="warningSevenItem" />
</template><script>
export default {data() {return {warningData: {high: [30, 40, 35, 50, 60, 40, 80],    // 高危数据middle: [70, 60, 65, 60, 60, 80, 70],  // 中危数据low: [50, 70, 80, 70, 60, 70, 60]      // 低危数据},warningSevenItem: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] // X轴标签}}
}
</script>

核心代码实现

1. 堆叠柱状图配置

// 核心实现:创建堆叠柱状图,三个系列分别代表低、中、高危
series: [{name: '低危',type: 'bar',stack: '总量',  // 设置堆叠,关键属性data: lowData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#70B2F7' },  // 顶部颜色{ offset: 0.5, color: '#52A2FF' }, // 中间颜色{ offset: 1, color: '#1970C2' }   // 底部颜色])}},{name: '中危',type: 'bar',stack: '总量',data: middleData,// 中危渐变色配置...},{name: '高危',type: 'bar',stack: '总量',data: highData,// 高危渐变色配置...}
]

2. 渐变色实现

// 通过LinearGradient创建渐变效果
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FF2E2E' },  // 顶部颜色(更鲜艳){ offset: 0.5, color: '#FF5252' }, // 中间颜色{ offset: 1, color: '#FF8A8A' }   // 底部颜色(过渡到中危)
]),

3. 数据提示框配置

tooltip: {trigger: 'axis',formatter: function(params) {const index = params[0].dataIndex;const date = xAxisData[index];const total = totalData[index] || 0;let result = `${date}<br/>总数: ${total}<br/>`;// 添加各危险级别数据params.forEach((param) => {let value = param.value || 0;result += `${param.seriesName}: ${value}<br/>`;});return result;}
}

4. 数据变化更新

// 监听数据变化,只在真正变化时更新图表
watch(() => [props.warningData, props.warningSevenItem], ([newWarningData, newWarningSevenItem]) => {const newWarningDataStr = JSON.stringify(newWarningData);const newWarningSevenItemStr = JSON.stringify(newWarningSevenItem);// 检查数据是否有变化const dataChanged = newWarningDataStr !== prevWarningData.value || newWarningSevenItemStr !== prevWarningSevenItem.value;if (dataChanged) {if (chartInstance) {updateChart();} else {initChart();}}
}, { deep: true });

自定义调整

  1. 修改显示顺序:调整series数组中三个对象的顺序即可改变柱状图中高中低危的堆叠顺序

  2. 调整颜色:修改各系列的LinearGradient配置可以改变渐变色效果

  3. 调整圆角:目前顶部系列设置了borderRadius: [2, 2, 0, 0]实现顶部圆角效果

完整组件代码:

<template><div ref="chartContainer" class="chart-container"><div ref="chart" class="chart"></div></div>
</template><script lang="ts">
import { defineComponent, onMounted, ref, watch, onUnmounted } from 'vue';
import * as echarts from 'echarts';export default defineComponent({name: 'JianbianZhu',props: {warningData: {type: Object,required: true},warningSevenItem: {type: Array,required: true}},setup(props) {const chartRef = ref<HTMLElement | null>(null);let chartInstance: echarts.ECharts | null = null;// 保存上一次的数据快照,用于比较数据是否变化const prevWarningData = ref<string>('');const prevWarningSevenItem = ref<string>('');// 处理窗口大小变化const handleResize = () => {if (chartInstance) {chartInstance.resize();}};const initChart = () => {if (!chartRef.value) return;// 创建图表实例chartInstance = echarts.init(chartRef.value);// 准备数据const xAxisData = props.warningSevenItem;const highData = props.warningData.high || [];const middleData = props.warningData.middle || [];const lowData = props.warningData.low || [];// 计算总数据用于展示const totalData = highData.map((val: number, index: number) => {return val + (middleData[index] || 0) + (lowData[index] || 0);});// 更新数据快照prevWarningData.value = JSON.stringify(props.warningData);prevWarningSevenItem.value = JSON.stringify(props.warningSevenItem);// 配置图表选项const option = {tooltip: {trigger: 'axis',axisPointer: {type: 'shadow'},formatter: function(params: any) {const index = params[0].dataIndex;const date = xAxisData[index];const total = totalData[index] || 0;let result = `${date}<br/>总数: ${total}<br/>`;// 按顺序添加高中低危数据params.forEach((param: any) => {let value = param.value || 0;result += `${param.seriesName}: ${value}<br/>`;});return result;}},legend: {data: ['低危', '中危', '高危'],textStyle: {color: 'rgba(255, 255, 255, 0.65)'},right: '5%',top: '0%'},grid: {left: '5%',right: '5%',bottom: '10%',top: '15%',containLabel: true},xAxis: {type: 'category',data: xAxisData,axisLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.2)'}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,interval: 0,rotate: 0},axisTick: {show: false}},yAxis: {type: 'value',name: '',nameTextStyle: {color: 'rgba(255, 255, 255, 0.65)'},min: 0,axisLine: {show: false},axisTick: {show: false},splitLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.1)',type: 'dashed',width: 0.5}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,formatter: function(value: number) {if (value >= 1000) {return Math.floor(value / 1000) + 'k';}return value;}}},series: [{name: '低危',type: 'bar',stack: '总量',data: lowData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#70B2F7' },  // 顶部颜色(与中危底部接近){ offset: 0.5, color: '#52A2FF' }, // 中间颜色{ offset: 1, color: '#1970C2' }   // 底部颜色(更深)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '中危',type: 'bar',stack: '总量',data: middleData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FFA066' },  // 顶部颜色(与高危底部接近){ offset: 0.5, color: '#FFA647' }, // 中间颜色{ offset: 1, color: '#FFD0A1' }   // 底部颜色(过渡到低危)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '高危',type: 'bar',stack: '总量',data: highData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FF2E2E' },  // 顶部颜色(更鲜艳){ offset: 0.5, color: '#FF5252' }, // 中间颜色{ offset: 1, color: '#FF8A8A' }   // 底部颜色(过渡到中危)]),borderRadius: [2, 2, 0, 0] // 只有最上面的柱子需要圆角},emphasis: {itemStyle: {opacity: 0.9}},z: 10},],backgroundColor: 'transparent'};// 设置图表选项chartInstance.setOption(option);// 监听窗口大小变化自动调整图表大小window.addEventListener('resize', handleResize);};// 更新图表,不销毁实例const updateChart = () => {if (!chartInstance || !chartRef.value) return;// 准备数据const xAxisData = props.warningSevenItem;const highData = props.warningData.high || [];const middleData = props.warningData.middle || [];const lowData = props.warningData.low || [];// 计算总数据用于展示const totalData = highData.map((val: number, index: number) => {return val + (middleData[index] || 0) + (lowData[index] || 0);});// 更新数据快照prevWarningData.value = JSON.stringify(props.warningData);prevWarningSevenItem.value = JSON.stringify(props.warningSevenItem);// 解决方案:创建完整的配置,使用true参数强制重置所有配置// 这将确保tooltip格式化器使用最新数据chartInstance.clear();  // 清除当前图表// 完整重新配置图表const option = {tooltip: {trigger: 'axis',axisPointer: {type: 'shadow'},formatter: function(params: any) {const index = params[0].dataIndex;const date = xAxisData[index];const total = totalData[index] || 0;let result = `${date}<br/>总数: ${total}<br/>`;// 按顺序添加高中低危数据params.forEach((param: any) => {let value = param.value || 0;result += `${param.seriesName}: ${value}<br/>`;});return result;}},legend: {data: ['高危', '中危', '低危'],textStyle: {color: 'rgba(255, 255, 255, 0.65)'},right: '5%',top: '0%'},grid: {left: '5%',right: '5%',bottom: '10%',top: '15%',containLabel: true},xAxis: {type: 'category',data: xAxisData,axisLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.2)'}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,interval: 0,rotate: 0},axisTick: {show: false}},yAxis: {type: 'value',name: '',nameTextStyle: {color: 'rgba(255, 255, 255, 0.65)'},min: 0,axisLine: {show: false},axisTick: {show: false},splitLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.1)',type: 'dashed',width: 0.5}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,formatter: function(value: number) {if (value >= 1000) {return Math.floor(value / 1000) + 'k';}return value;}}},series: [{name: '高危',type: 'bar',stack: '总量',data: highData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FF2E2E' },  // 顶部颜色(更鲜艳){ offset: 0.5, color: '#FF5252' }, // 中间颜色{ offset: 1, color: '#FF8A8A' }   // 底部颜色(过渡到中危)]),borderRadius: [2, 2, 0, 0] // 只有最上面的柱子需要圆角},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '中危',type: 'bar',stack: '总量',data: middleData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FFA066' },  // 顶部颜色(与高危底部接近){ offset: 0.5, color: '#FFA647' }, // 中间颜色{ offset: 1, color: '#FFD0A1' }   // 底部颜色(过渡到低危)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '低危',type: 'bar',stack: '总量',data: lowData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#70B2F7' },  // 顶部颜色(与中危底部接近){ offset: 0.5, color: '#52A2FF' }, // 中间颜色{ offset: 1, color: '#1970C2' }   // 底部颜色(更深)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10}],backgroundColor: 'transparent'};// 使用完整配置重新初始化图表chartInstance.setOption(option);};// 在组件挂载后初始化图表onMounted(() => {initChart();});// 监听数据变化,仅在数据真正变化时更新图表watch(() => [props.warningData, props.warningSevenItem], ([newWarningData, newWarningSevenItem]) => {const newWarningDataStr = JSON.stringify(newWarningData);const newWarningSevenItemStr = JSON.stringify(newWarningSevenItem);// 检查数据是否有变化const dataChanged = newWarningDataStr !== prevWarningData.value || newWarningSevenItemStr !== prevWarningSevenItem.value;if (dataChanged) {// 如果数据有变化,更新图表if (chartInstance) {updateChart();} else {initChart();}}}, { deep: true });// 组件卸载时清理资源onUnmounted(() => {if (chartInstance) {// 移除resize事件监听window.removeEventListener('resize', handleResize);chartInstance.dispose();chartInstance = null;}});return {chart: chartRef};}
});
</script><style scoped>
.chart-container {width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;
}.chart {width: 100%;height: 100%;min-height: 280px;
}
</style>

相关文章:

封装渐变堆叠柱状图组件附完整代码

组件功能 这是一个渐变堆叠柱状图组件&#xff0c;主要功能包括&#xff1a; 在一根柱子上同时显示高、中、低三种危险级别数据使用渐变色区分不同危险级别&#xff08;高危红色、中危橙色、低危蓝色&#xff09;悬停显示详细数据信息&#xff08;包括总量和各级别数据&#…...

分布式项目保证消息幂等性的常见策略

Hello&#xff0c;大家好&#xff0c;我是灰小猿&#xff01; 在分布式系统中&#xff0c;由于各个服务之间独立部署&#xff0c;各个服务之间依靠远程调用完成通信&#xff0c;再加上面对用户重复点击时的重复请求等情况&#xff0c;所以如何保证消息消费的幂等性是在分布式或…...

山东大学软件学院创新项目实训开发日志——第十三周

目录 1.开展prompt工程&#xff0c;创建个性化AI助理&#xff0c;能够基于身份实现不同角度和语言风格的回答。 2.对输出进行格式化&#xff0c;生成特定格式的会议计划文档。 3.学习到的新知识 本阶段我所做的工作 1.开展prompt工程&#xff0c;创建个性化AI助理&#xff…...

如何在sublime text中批量为每一行开头或者结尾添加删除指定内容

打开你的文件&#xff1a;首先&#xff0c;在 Sublime Text 中打开你想要编辑的文件&#xff0c;然后全选 行首插入&#xff1a; 选择所有行的开头&#xff1a; 使用快捷键 Ctrl Shift L&#xff08;Windows/Linux&#xff09;或 Cmd Shift L&#xff08;Mac&#xff09;&…...

Cesium 透明渐变墙 解决方案

闭合路径修复 通过增加额外点确保路径首尾相接 透明渐变效果 使用RGBA颜色模式实现从完全不透明到完全透明的平滑渐变 参数可调性 提供多个可调参数&#xff0c;轻松自定义颜色、高度和圆环尺寸 完整代码实现 <!DOCTYPE html> <html> <head><meta …...

网络原理与 TCP/IP 协议详解

一、网络通信的本质与基础概念 1.1 什么是网络通信&#xff1f; 网络通信的本质是跨设备的数据交换&#xff0c;其核心目标是让不同物理位置的设备能够共享信息。这种交换需要解决三个核心问题&#xff1a; 如何定位设备&#xff1f; → IP地址如何找到具体服务&#xff1f;…...

day022-定时任务-故障案例与发送邮件

文章目录 1. cron定时任务无法识别命令1.1 故障原因1.2 解决方法1.2.1 对命令使用绝对路径1.2.2 在脚本开头定义PATH 2. 发送邮件2.1 安装软件2.2 配置邮件信息2.3 巡检脚本与邮件发送2.3.1 巡检脚本内容2.3.2 制作时任务发送邮件 3. 调取API发送邮件3.1 编写文案脚本3.2 制作定…...

新增 git submodule 子模块

文章目录 1、基本语法2、添加子模块后的操作3、拉取带有submodule的仓库 git submodule add 是 Git 中用于将另一个 Git 仓库作为子模块添加到当前项目中的命令。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录&#xff0c;同时保持它们各自的提交历史独立。 1、基…...

List优雅分组

一、前言 最近小永哥发现&#xff0c;在开发过程中&#xff0c;经常会遇到需要对list进行分组&#xff0c;就是假如有一个RecordTest对象集合&#xff0c;RecordTest对象都有一个type的属性&#xff0c;需要将这个集合按type属性进行分组&#xff0c;转换为一个以type为key&…...

Linux 使用 Docker 安装 Milvus的两种方式

一、使用 Docker Compose 运行 Milvus (Linux) 安装并启动 Milvus Milvus 在 Milvus 资源库中提供了 Docker Compose 配置文件。要使用 Docker Compose 安装 Milvus&#xff0c;只需运行 wget https://github.com/milvus-io/milvus/releases/download/v2.5.10/milvus-standa…...

AR眼镜+AI视频盒子+视频监控联网平台:消防救援的智能革命

在火灾现场&#xff0c;每一秒都关乎生死。传统消防救援方式面临信息滞后、指挥盲区、环境复杂等挑战。今天&#xff0c;一套融合AR智能眼镜AI视频分析盒子智能监控管理平台的"三位一体"解决方案&#xff0c;正在彻底改变消防救援的作业模式&#xff0c;为消防员装上…...

编程技能:字符串函数10,strchr

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程技能&#xff1a;字符串函数09&#xff0c;strncmp 回到目录…...

使用tunasync部署企业内部开源软件镜像站-Centos Stream 9

使用tunasync部署企业内部开源软件镜像站 tunasync 是清华大学 TUNA 镜像源目前使用的镜像方案&#xff0c;本文将介绍如何使用 tunasync 部署企业内部开源软件镜像站。 基于tunasync mirror-web nginx进行镜像站点搭建。 1. tunasync设计 tunasync架构如下&#xff1a; …...

c/c++的opencv像素级操作二值化

图像级操作&#xff1a;使用 C/C 进行二值化 在数字图像处理中&#xff0c;图像级操作 (Image-Level Operations) 是指直接在图像的像素级别上进行处理&#xff0c;以改变图像的视觉特性或提取有用信息。这些操作通常不依赖于图像的全局结构&#xff0c;而是关注每个像素及其邻…...

C++----Vector的模拟实现

上一节讲了string的模拟实现&#xff0c;string的出现时间比vector靠前&#xff0c;所以一些函数给的也比较冗余&#xff0c;而后来的vector、list等在此基础上做了优化。这节讲一讲vector的模拟实现&#xff0c;vector与模板具有联系&#xff0c;而string的底层就是vector的一…...

Mac redis下载和安装

目录 1、官网&#xff1a;https://redis.io/ 2、滑到最底下 3、下载资源 4、安装&#xff1a; 5、输入 sudo make test 进行编译测试 会提示 ​编辑 6、sudo make install 继续 7、输入 src/redis-server 启动服务器 8、输入 src/redis-cli 启动测试端 1、官网&#xff…...

[25-cv-05718]BSF律所代理潮流品牌KAWS公仔(商标+版权)

潮流品牌KAWS公仔 案件号&#xff1a;25-cv-05718 立案时间&#xff1a;2025年5月21日 原告&#xff1a;KAWS, INC. 代理律所&#xff1a;Boies Schiller Flexner LLP 原告介绍 原告是一家由美国街头艺术家Brian Donnelly创立的公司&#xff0c;成立于2002年2月25日&…...

【PhysUnits】9 取负重载(negation.rs)

一、源码 这段代码是类型级二进制数&#xff08;包括正数和负数&#xff09;的取反和取负操作。它使用了类型系统来表示二进制数&#xff0c;并通过特质&#xff08;trait&#xff09;和泛型来实现递归操作。 use super::basic::{B0, B1, Z0, N1}; use core::ops::Neg;// 反…...

深度思考、弹性实施,业务流程自动化的实践指南

随着市场环境愈发复杂化&#xff0c;各类型企业的业务步伐为了跟得上市场节奏也逐步变得紧张&#xff0c;似乎只有保持极强的竞争力、削减成本、提升抗压能力才能在市场洪流中博得一席之位。此刻企业需要制定更明智的解决方案&#xff0c;以更快、更准确地优化决策流程。与简单…...

UWB:litepoint获取txquality里面的NRMSE

在使用litepoint测试UWB,获取txquality里面的NRMSE时,网页端可以正常获取NRMSE。但是通过SCPI 命令来获取NRMSE一直出错。 NRMSE数据类型和pyvisa问题: 参考了user guide,发现NRMSE的数值是ARBITRARY_BLOCK FLOAT,非string。 pyvisa无法解析会返回错误。 查询了各种办法…...

VUE npm ERR! code ERESOLVE, npm ERR! ERESOLVE could not resolve, 错误有效解决

VUE &#xff1a; npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve 错误有效解决 npm install 安装组件的时候出现以上问题&#xff0c;npm版本问题报错解决方法&#xff1a;用上述方法安装完成之后又出现其他的问题 npm install 安装组件的时候出现以上问题&…...

IoT/HCIP实验-1/物联网开发平台实验Part1(快速入门,MQTT.fx对接IoTDA)

文章目录 实验介绍设备接入IoTDA进入IoTDA平台什么是IoTDA 开通服务创建产品和设备定义产品模型&#xff08;Profile&#xff09;设备注册简思(实例-产品-设备) 模拟.与平台通信虚拟设备/MQTT.fx应用 Web 控制台QA用户或密码错误QA证书导致的连接失败设备与平台连接成功 上报数…...

DMA STM32H7 Domains and space distrubution

DMA这个数据搬运工&#xff0c;对谁都好&#xff0c;任劳任怨&#xff0c;接受雇主设备的数据搬运业务。每天都忙碌着&#xff01;哈哈哈。 1. DMA 不可能单独工作&#xff0c;必须接收其他雇主的业务&#xff0c;所以数据搬运业务的参与者是DMA本身和业务需求发起者。 2. 一…...

洪水危险性评价与风险防控全攻略:从HEC-RAS数值模拟到ArcGIS水文分析,一键式自动化工具实战,助力防洪减灾与应急管理

&#x1f50d; 洪水淹没危险性是洪水损失评估、风险评估及洪水应急和管理规划等工作的重要基础。当前&#xff0c;我国正在开展的自然灾害风险普查工作&#xff0c;对洪水灾害给予了重点关注&#xff0c;提出了对洪水灾害危险性及风险评估的明确要求。洪水危险性及风险评估通常…...

Gemini Pro 2.5 输出

好的&#xff0c;我已经按照您的要求&#xff0c;将顶部横幅提示消息修改为右下角的 Toast 样式通知。 以下是涉及更改的文件及其内容&#xff1a; 1. my/src/html-ui.js 移除了旧的 #message-area div。在 <body> 底部添加了新的 #toast-container div 用于存放 Toas…...

SQL Server 和 MySQL 对比

下面是 SQL Server 和 MySQL 的详细对比&#xff0c;从功能、性能、成本、生态等多个维度展开&#xff0c;帮助你判断在什么情况下该选择哪一个。 ✅ 总览对比表 维度SQL ServerMySQL开发公司微软&#xff08;Microsoft&#xff09;Oracle&#xff08;2008年起&#xff09;是否…...

Leetcode 3269. 构建两个递增数组

1.题目基本信息 1.1.题目描述 给定两个只包含 0 和 1 的整数数组 nums1 和 nums2&#xff0c;你的任务是执行下面操作后使数组 nums1 和 nums2 中 最大 可达数字 尽可能小。 将每个 0 替换为正偶数&#xff0c;将每个 1 替换为正奇数。在替换后&#xff0c;两个数组都应该 递…...

三轴云台之积分分离PID控制算法篇

一、核心原理 积分分离PID控制的核心在于动态调整积分项的作用&#xff0c;以解决传统PID在三轴云台应用中的超调、振荡问题&#xff1a; 大误差阶段&#xff08;如云台启动或快速调整时&#xff09;&#xff1a; 关闭积分项&#xff0c;仅使用比例&#xff08;P&#xff09;…...

【Elasticsearch】scripted_upsert

在 Elasticsearch 中&#xff0c;scripted_upsert 是一个用于更新操作的参数&#xff0c;它允许在文档不存在时通过脚本初始化文档内容&#xff0c;而不是直接使用 upsert 部分的内容。这种方式提供了更灵活的文档创建和更新逻辑。 scripted_upsert 的工作原理 当设置 scripte…...

uv - 一个现代化的项目+环境管理工具

参考&#xff1a; 【uv】Python迄今最好的项目管理环境管理工具&#xff08;吧&#xff1f;&#xff09;_哔哩哔哩_bilibili 项目需求 想象&#xff0c;每次创建一个项目的时候&#xff0c;我们需要去写 README. md, .git 仓库, .gitignore&#xff0c;你会感觉很头大 对于 …...