首页 > 其他分享 >Luckysheet 的使用以及踩坑

Luckysheet 的使用以及踩坑

时间:2024-07-10 16:41:46浏览次数:10  
标签:Luckysheet const 以及 cell luckysheet let 使用 return border

最近在项目中遇到了需要实现一个类似于excel功能的需求,同时需要实现excel的导入导出以及打印功能。接下来介绍一下使用luckysheet的过程以及过程中遇到的一些问题以及解决方案。

1. 使用

1.1 引入

lucky是一个比较老的项目,所以引入方式建议使用全局方式引入。虽然也有npm包,但是在使用的时候并不能如愿。

CDN引入

类似于jQuery一样,lucky需要使用全局引入的方式进行引入,如果使用的是框架,例如vue,可以在publicindex.html中进行一引入。这样会产生一个全局的luckysheet对象。

<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/assets/iconfont/iconfont.css' />
<script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/luckysheet.umd.js"></script>

本地引入

在一些内部网络环境或者使用CDN不理想的情况下,可以使用本地资源包的方式引入

<link rel="stylesheet" href="static/luckysheet/dists/plugins/css/pluginsCss.css" />
<link rel="stylesheet" href="static/luckysheet/dists/plugins/plugins.css" />
<link rel="stylesheet" href="static/luckysheet/dists/css/luckysheet.css" />
<link rel="stylesheet" href="static/luckysheet/dists/assets/iconfont/iconfont.css" />
<script src="static/luckysheet/dists/plugins/js/plugin.js"></script>
<script src="static/luckysheet/dists/luckysheet.umd.js"></script>

静态资源包可以下载源码之后进行打包生成,也可以直接寻找资源下载。这里提供一个CDN下载地址https://www.jsdelivr.com/package/npm/luckysheet。当然如果有对源码修改的需求(后面会说到),就得必须使用源码打包的方式了。

1.2 使用

luckysheet需要一个容器进行表格的创建。所以需要在代码中设置一个容器

<div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;height:100%;left: 0px;top: 0px;"></div>

创建表格的时候需要在配置中指定容器

 var options = {
     container: 'luckysheet' //luckysheet为容器id
}

在引入luckysheet资源文件之后,会在全局产生一个luckysheet对象,使用这个对象即可创建表格

window.luckysheet.create(this.options);

这里的option表示配置参数,具体可以参考配置文档:https://dream-num.github.io/LuckysheetDocs/zh/guide/

概念

一个完整的Luckysheet表格文件的数据格式为:luckysheetfile,一个表格文件包含若干个sheet文件,对应excel的sheet0、sheet1等。

一个Luckysheet文件的示例如下,该表格包含3个sheet:luckysheetfile = [ {sheet1设置}, {sheet2设置}, {sheet3设置} ] 相当于excel的3个sheet

image-20240710110440204

文件中的一个sheet的数据luckysheetfile[0]的结构如下:

{
	"name": "Cell", //工作表名称
	"color": "", //工作表颜色
	"index": "0", //工作表索引
	"status": "1", //激活状态
	"order": "0", //工作表的顺序
	"hide": 0,//是否隐藏
	"row": 36, //行数
	"column": 18, //列数
	"config": {
		"merge":{}, //合并单元格
		"rowlen":{}, //表格行高
		"columnlen":{}, //表格列宽
		"rowhidden":{}, //隐藏行
		"colhidden":{}, //隐藏列
		"borderInfo":{}, //边框
	},
	"celldata": [], //初始化使用的单元格数据
	"data": [], //更新和存储使用的单元格数据
	"scrollLeft": 0, //左右滚动条位置
	"scrollTop": 315, //上下滚动条位置
	"luckysheet_select_save": [], //选中的区域
	"luckysheet_conditionformat_save": {},//条件格式
	"calcChain": [],//公式链
	"isPivotTable":false,//是否数据透视表
	"pivotTable":{},//数据透视表设置
	"filter_select": {},//筛选范围
	"filter": null,//筛选配置
	"luckysheet_alternateformat_save": [], //交替颜色
	"luckysheet_alternateformat_save_modelCustom": [], //自定义交替颜色	
	"freezen": {}, //冻结行列
	"chart": [], //图表配置
	"visibledatarow": [], //所有行的位置
	"visibledatacolumn": [], //所有列的位置
	"ch_width": 2322, //工作表区域的宽度
	"rh_height": 949, //工作表区域的高度
	"load": "1", //已加载过此sheet的标识
}

以上就是基本使用方式了,接下来为扩展实现的功能

2. 权限编辑

需求是有些人具有编辑权限,有些人只有查看权限,这个实现起来比较简单。根据权限设置option中的allowEdit的值。然后再进行表格创建即可。具体来说就是具有权限的人员设置allowEdit为true。不具有权限的人员设置为false。当然在实现方式上也可以默认所有人不可编辑,然后使用按钮权限的方式进行控制,比如可以给有权限的人显示一个编辑按钮。没有权限的人不显示。

 <el-button type="warning" icon="icon-baocun" :loading="false" @click="openEdit" v-if="!options.allowEdit">编辑</el-button>
 <el-button type="warning" icon="icon-baocun" :loading="false" @click="saveData" v-else>保存</el-button>
// 开启编辑
openEdit() {
  this.options.allowEdit = true;
  window.luckysheet.create(this.options);
},

3.导入

本地导入关键代码,这里使用的是element的文件上传组件,使用luckyexcel 读取文件内容。

安装

npm install luckyexcel 

引入

import LuckyExcel from 'luckyexcel';

上传交互

<el-button type="primary" icon="jy-icon-daoru" :loading="false" @click="openUpDialog">本地导入</el-button>
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%" class="dialog">
  <el-upload class="upload-demo" action="" :on-change="fileChange" drag accept=".xlsx" style="width: 100%" :auto-upload="false">
    <i class="el-icon-upload"></i>
    <div class="el-upload__text">
      将文件拖到此处,或
      <em>点击上传</em>
    </div>
    <div class="el-upload__tip">只能上传xlsx文件,且不超过500kb</div>
  </el-upload>
  <span slot="footer" class="dialog-footer">
    <el-button type="primary" @click="doImport">确 定</el-button>
    <el-button @click="cancelImport()">取 消</el-button>
  </span>
</el-dialog>

需要将自动上传关闭,然后监听文件变化,

// 打开上传更换弹窗
openUpDialog() {
  this.dialogVisible = true;
},
// 上传文件变化
fileChange(file) {
  this.file = file.raw;
},
// 执行上传确认操作
doImport() {
  if (!this.file) return;
  this.uploadExcel();
  this.dialogVisible = false;
},
// 取消上传
cancelImport() {
  this.file = null;
  this.dialogVisible = false;
},

在确认上传之后获取到上传的文件的内容使用luckyexcel内置apitransformExcelToLucky 转化为JSON数据,然后再进行表格的创建。

// 本地导入
uploadExcel() {
  LuckyExcel.transformExcelToLucky(this.file, (exportJson) => {
    if (exportJson.sheets == null || exportJson.sheets.length == 0) {
      alert('当前仅支持xlsx文件导入!');
      return;
    }
    console.log(exportJson);
    window.luckysheet.destroy();
    this.options.data = exportJson.sheets;
    window.luckysheet.create(this.options);
  });
},

4.导出

导出使用的是exceljs 以及 file-saver 实现的。自行安装这俩个包,然后创建一个export.js 。

import Excel from 'exceljs';
import FileSaver from 'file-saver';

export var exportExcel = function (luckysheet, value) {
  // 1.创建工作簿,可以为工作簿添加属性
  const workbook = new Excel.Workbook();
  // 2.创建表格,第二个参数可以配置创建什么样的工作表
  luckysheet.forEach(function (table) {
    if (table.data.length === 0) return true;
    const worksheet = workbook.addWorksheet(table.name);
    const merge = (table.config && table.config.merge) || {};
    const borderInfo = (table.config && table.config.borderInfo) || {};
    // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值,导出图片
    setStyleAndValue(table.data, worksheet);
    setMerge(merge, worksheet);
    setBorder(borderInfo, worksheet);
    setImages(table.images, worksheet, workbook);
    return true;
  });

  // 4.写入 buffer
  const buffer = workbook.xlsx.writeBuffer().then((data) => {
    const blob = new Blob([data], {
      type: 'application/vnd.ms-excel;charset=utf-8',
    });
    console.log('导出成功!');
    FileSaver.saveAs(blob, `${value}.xlsx`);
  });
  return buffer;
};

var setMerge = function (luckyMerge = {}, worksheet) {
  const mergearr = Object.values(luckyMerge);
  mergearr.forEach(function (elem) {
    // elem格式:{r: 0, c: 0, rs: 1, cs: 2}
    // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)
    worksheet.mergeCells(elem.r + 1, elem.c + 1, elem.r + elem.rs, elem.c + elem.cs);
  });
};

var setBorder = function (luckyBorderInfo, worksheet) {
  if (!Array.isArray(luckyBorderInfo)) return;
  // console.log('luckyBorderInfo', luckyBorderInfo)
  luckyBorderInfo.forEach(function (elem) {
    // 现在只兼容到borderType 为range的情况
    // console.log('ele', elem)
    if (elem.rangeType === 'range') {
      let border = borderConvert(elem.borderType, elem.style, elem.color);
      let rang = elem.range[0];
      // console.log('range', rang)
      let row = rang.row;
      let column = rang.column;
      for (let i = row[0] + 1; i < row[1] + 2; i++) {
        for (let y = column[0] + 1; y < column[1] + 2; y++) {
          worksheet.getCell(i, y).border = border;
        }
      }
    }
    if (elem.rangeType === 'cell') {
      // col_index: 2
      // row_index: 1
      // b: {
      //   color: '#d0d4e3'
      //   style: 1
      // }
      const { col_index, row_index } = elem.value;
      const borderData = Object.assign({}, elem.value);
      delete borderData.col_index;
      delete borderData.row_index;
      let border = addborderToCell(borderData, row_index, col_index);
      // console.log('bordre', border, borderData)
      worksheet.getCell(row_index + 1, col_index + 1).border = border;
    }
    // console.log(rang.column_focus + 1, rang.row_focus + 1)
    // worksheet.getCell(rang.row_focus + 1, rang.column_focus + 1).border = border
  });
};
var setStyleAndValue = function (cellArr, worksheet) {
  if (!Array.isArray(cellArr)) return;
  cellArr.forEach(function (row, rowid) {
    row.every(function (cell, columnid) {
      if (!cell) return true;
      let fill = fillConvert(cell.bg);

      let font = fontConvert(cell.ff, cell.fc, cell.bl, cell.it, cell.fs, cell.cl, cell.ul);
      let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr);
      let value = '';

      if (cell.f) {
        value = { formula: cell.f, result: cell.v };
      } else if (!cell.v && cell.ct && cell.ct.s) {
        // xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后
        // value = cell.ct.s[0].v
        cell.ct.s.forEach((arr) => {
          value += arr.v;
        });
      } else {
        value = cell.v;
      }
      //  style 填入到_value中可以实现填充色
      let letter = createCellPos(columnid);
      let target = worksheet.getCell(letter + (rowid + 1));
      // console.log('1233', letter + (rowid + 1))
      for (const key in fill) {
        target.fill = fill;
        break;
      }
      target.font = font;
      target.alignment = alignment;
      target.value = value;

      return true;
    });
  });
};

var setImages = function (imagesArr, worksheet, workbook) {
  if (typeof imagesArr != 'object') return;
  for (let key in imagesArr) {
    // console.log(imagesArr[key]);
    // 通过 base64  将图像添加到工作簿
    const myBase64Image = imagesArr[key].src;
    //开始行 开始列 结束行 结束列
    const start = { col: imagesArr[key].fromCol, row: imagesArr[key].fromRow };
    const end = { col: imagesArr[key].toCol, row: imagesArr[key].toRow };
    const imageId = workbook.addImage({
      base64: myBase64Image,
      extension: 'png',
    });
    worksheet.addImage(imageId, {
      tl: start,
      br: end,
      editAs: 'oneCell',
    });
  }
};

var fillConvert = function (bg) {
  if (!bg) {
    return {};
  }
  // const bgc = bg.replace('#', '')
  let fill = {
    type: 'pattern',
    pattern: 'solid',
    fgColor: { argb: bg.replace('#', '') },
  };
  return fill;
};

var fontConvert = function (ff = 0, fc = '#000000', bl = 0, it = 0, fs = 10, cl = 0, ul = 0) {
  // luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
  const luckyToExcel = {
    0: '微软雅黑',
    1: '宋体(Song)',
    2: '黑体(ST Heiti)',
    3: '楷体(ST Kaiti)',
    4: '仿宋(ST FangSong)',
    5: '新宋体(ST Song)',
    6: '华文新魏',
    7: '华文行楷',
    8: '华文隶书',
    9: 'Arial',
    10: 'Times New Roman ',
    11: 'Tahoma ',
    12: 'Verdana',
    num2bl: function (num) {
      return num === 0 ? false : true;
    },
  };
  // 出现Bug,导入的时候ff为luckyToExcel的val

  let font = {
    name: typeof ff === 'number' ? luckyToExcel[ff] : ff,
    family: 1,
    size: fs,
    color: { argb: fc.replace('#', '') },
    bold: luckyToExcel.num2bl(bl),
    italic: luckyToExcel.num2bl(it),
    underline: luckyToExcel.num2bl(ul),
    strike: luckyToExcel.num2bl(cl),
  };

  return font;
};

var alignmentConvert = function (vt = 'default', ht = 'default', tb = 'default', tr = 'default') {
  // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
  const luckyToExcel = {
    vertical: {
      0: 'middle',
      1: 'top',
      2: 'bottom',
      default: 'top',
    },
    horizontal: {
      0: 'center',
      1: 'left',
      2: 'right',
      default: 'left',
    },
    wrapText: {
      0: false,
      1: false,
      2: true,
      default: false,
    },
    textRotation: {
      0: 0,
      1: 45,
      2: -45,
      3: 'vertical',
      4: 90,
      5: -90,
      default: 0,
    },
  };

  let alignment = {
    vertical: luckyToExcel.vertical[vt],
    horizontal: luckyToExcel.horizontal[ht],
    wrapText: luckyToExcel.wrapText[tb],
    textRotation: luckyToExcel.textRotation[tr],
  };
  return alignment;
};

var borderConvert = function (borderType, style = 1, color = '#000') {
  // 对应luckysheet的config中borderinfo的的参数
  if (!borderType) {
    return {};
  }
  const luckyToExcel = {
    type: {
      'border-all': 'all',
      'border-top': 'top',
      'border-right': 'right',
      'border-bottom': 'bottom',
      'border-left': 'left',
    },
    style: {
      0: 'none',
      1: 'thin',
      2: 'hair',
      3: 'dotted',
      4: 'dashDot', // 'Dashed',
      5: 'dashDot',
      6: 'dashDotDot',
      7: 'double',
      8: 'medium',
      9: 'mediumDashed',
      10: 'mediumDashDot',
      11: 'mediumDashDotDot',
      12: 'slantDashDot',
      13: 'thick',
    },
  };
  let template = {
    style: luckyToExcel.style[style],
    color: { argb: color.replace('#', '') },
  };
  let border = {};
  if (luckyToExcel.type[borderType] === 'all') {
    border['top'] = template;
    border['right'] = template;
    border['bottom'] = template;
    border['left'] = template;
  } else {
    border[luckyToExcel.type[borderType]] = template;
  }
  // console.log('border', border)
  return border;
};

function addborderToCell(borders, row_index, col_index) {
  let border = {};
  const luckyExcel = {
    type: {
      l: 'left',
      r: 'right',
      b: 'bottom',
      t: 'top',
    },
    style: {
      0: 'none',
      1: 'thin',
      2: 'hair',
      3: 'dotted',
      4: 'dashDot', // 'Dashed',
      5: 'dashDot',
      6: 'dashDotDot',
      7: 'double',
      8: 'medium',
      9: 'mediumDashed',
      10: 'mediumDashDot',
      11: 'mediumDashDotDot',
      12: 'slantDashDot',
      13: 'thick',
    },
  };
  // console.log('borders', borders)
  for (const bor in borders) {
    // console.log(bor)
    if (borders[bor].color.indexOf('rgb') === -1) {
      border[luckyExcel.type[bor]] = {
        style: luckyExcel.style[borders[bor].style],
        color: { argb: borders[bor].color.replace('#', '') },
      };
    } else {
      border[luckyExcel.type[bor]] = {
        style: luckyExcel.style[borders[bor].style],
        color: { argb: borders[bor].color },
      };
    }
  }

  return border;
}

function createCellPos(n) {
  let ordA = 'A'.charCodeAt(0);

  let ordZ = 'Z'.charCodeAt(0);
  let len = ordZ - ordA + 1;
  let s = '';
  while (n >= 0) {
    s = String.fromCharCode((n % len) + ordA) + s;

    n = Math.floor(n / len) - 1;
  }
  return s;
}

引入函数对象

import { exportExcel } from '@/util/export';

点击导出按钮执行导出函数

downloadExcel() {
	var time = dayjs(this.date).format('YYYY-MM-DD');
	var type = this.type == 'day' ? '日报' : '旬报';
	exportExcel(luckysheet.getAllSheets(), time + '_' + type);
},

这里补充一下,按钮可以使用定位的方式放在表格的头部。当然也可以使用自定义头部菜单的方式实现。我这里需要突出这几个功能,所以使用的是外置菜单的方式。

image-20240710112824653

还有一些可能不使用的元素可以直接在option的hook里面去掉。

hook: {
  workbookCreateAfter: function () {
    // 删除表格信息栏后侧的两个显示信息
    $('.luckysheet_info_detail_save').html('');
    $('.luckysheet_info_detail_update').html('');
  },
},

5. 打印

luckysheet的打印功能是唯一一个收费项目,也希望大家多多支持开源,可以一次性永久买断这个功能。我这里介绍的是一种折中的实现方式,主要的实现思路是使用luckysheet提供的选区以及截图的方式来间接实现打印功能。这里有两种实现方案。
两种都需要先在文档中创建一个用于实现打印的区域或者说容器

<el-button type="primary" icon="el-icon-printer" :loading="false" @click="printExcel" v-print="'#print_html'">打印</el-button>

<!--    打印内容区域,默认不显示,点击打印后才显示-->
<div id="print-area" style="display: none; position: absolute; z-index: 0; top: 0; width: 100%; height: 100vh; overflow: hidden">
  <div id="print_html" style="text-align: center" ref="printRef"></div>
</div>

然后使用

方案一:模拟点击全选实现所有表格的选中

// 打印实现
printExcel() {
  // 1. 实现全选
  $('#luckysheet-left-top').click();
  // 2. 生成选区的截图
  let src = luckysheet.getScreenshot();
  let $img = `<img src=${src} style="max-width: 90%;" />`;
  this.$nextTick(() => {
    document.querySelector('#print_html').innerHTML = $img;
  });
},

方案二: 使用选区然后再截图

// 打印实现
printExcel() {
  let RowColumn = this.getExcelRowColumn(); // 获取有值的行和列
  console.log(RowColumn);
  RowColumn.column[0] = 0; //因需要打印左边的边框,需重新设置
  luckysheet.setRangeShow(RowColumn); // 进行选区操作
  let src = luckysheet.getScreenshot(); // 生成base64图片
  let $img = `<img src=${src} style="max-width: 90%;" />`;
  this.$nextTick(() => {
    document.querySelector('#print_html').innerHTML = $img;
  });
},

这里有个关键的指令 v-print="'#print_html'" ,所使用的是vue-print-nb 打印插件

vue-print-nb 插件

安装引入插件

vue2

npm install vue-print-nb --save

vue3

npm install vue3-print-nb --save

在main.js中引入

Vue2

import Print from 'vue-print-nb'

Vue.use(Print) 

Vue3

import { createApp } from 'vue'
import App from './App.vue'
import print from 'vue3-print-nb'
const app = createApp(App)
app.use(print)
app.mount('#app')

插件使用

<button v-print="'#printMe'">打印按钮</button>
<div id="printMe">打印区域<div>

6. 踩坑

6.1 dists 文件被git过滤

这个问题应该是小概率问题。遇到这个问题是因为我使用了本地的资源包,但是这个资源包中内容放在dists文件夹中,凑巧的是 .gitignore文件中忽略了所有的dists文件,所以造成团队其他成员在打包之后缺失了这个组件的文件。

image-20240710142234366

解决方案:删除dists这一层文件夹或者去除git过滤dists

6.2 qiankun微应用丢失图标

image-20240710142634760

image-20240710142705726

当使用的项目是qiankun微应用的时候,会造成部分图标丢失的问题,这是因为乾坤会将微应用的css抽取出来做成内联的style样式。但是在luckysheet内部具有相对路径的引入iconfont文件。这样就会造成字体文件丢失。

image-20240710143124435

解决办法: 将这个文件中的所有字体引入换成绝对路径

image-20240710143249569

6.3 打印最左侧与上侧边框丢失

image-20240710143657934

实现方案一:在表格的最左侧添加一列,并将列的宽度设置的足够小。在打印时实现视觉上没有就可以使用第二列的边框作为最左侧的边框,上边框同理

image-20240710143911310

实现方案二:在源码中本身其实具有添加左边与上边的边框的代码,但是由于使用的颜色与边框颜色不同所以显示不正常。对代码进行修改之后再次打包。

源代码中的内容:

image-20240710144211603

修改为

image-20240710160317383

然后再进行打包即可:下载地址: https://gitee.com/cxymds/files/blob/master/luckysheet.zip

标签:Luckysheet,const,以及,cell,luckysheet,let,使用,return,border
From: https://www.cnblogs.com/Cxymds/p/18294420

相关文章

  • 价格预言机的使用总结(三):UniswapV3篇
    文章首发于公众号:Keegan小钢前言前面两篇文章分别讲解了Chainlink和UniswapV2的TWAP。Chainlink属于链下预言机,其价格源取自多个交易所,但所支持的token比较有限,主要适用于获取主流token的价格。UniswapV2的TWAP则是链上预言机,可适用于获取Uniswap上已......
  • windows下使用dockerdesktop进行部署
    Docker部署springboot项目环境准备要在windows上使用docker需要确认系统的需求需要启用虚拟化支持的CPU启用适用于windows的Linux子系统功能保证足够的内存下载dockerdesktop下载后会提示安装对应的环境坑点安装过程中需要安装wsl环境,会遇到0x80370102问题。根据......
  • 今天晚上要看一下整车网络拓扑和CAN同学以及DBC文件
    https://mp.weixin.qq.com/s/UE8qqWCZxhq-yHzJb_VUawhttps://mp.weixin.qq.com/s?__biz=MzkzNzUwNDQ2NQ==&mid=2247486855&idx=1&sn=d1aa60630dd731f9bf8a662a65d29675&chksm=c28f3639f5f8bf2ff02b7eea4d24b772391fcfc02e51626b149f977bd3e8071e65a8566629f2......
  • lombok 怎么解决子父类继承的时候使用的问题
    在Java中使用Lombok来简化JavaBean的开发时,处理继承关系可能会遇到一些问题。Lombok的注解,如@Getter、@Setter、@ToString等,默认不会处理继承的字段和方法。这会导致子类无法自动继承父类的Lombok注解生成的方法。以下是一些解决继承问题的建议和示例代码:在父类和子类中分别使......
  • 设计模式使用场景实现示例及优缺点(创建型模式——单例模式、建造者模式、原型模式)
    创建型模式单例模式(SingletonPattern)单例模式(SingletonPattern)在Java中的使用场景与在其他编程语言中类似,其主要目的是确保一个类只有一个实例,并提供一个全局的访问点。以下是单例模式的一些常见使用场景及详细讲解:使用场景控制资源的使用:数据库连接池:数据库连接是......
  • 设计模式使用场景实现示例及优缺点(结构型模式——代理模式、外观模式)
    结构型模式代理模式(ProxyPattern)代理模式(ProxyPattern)是一种结构型设计模式,它通过引入一个代理对象来控制对另一个对象的访问。这个代理对象可以为被代理的对象提供额外的功能,例如访问控制、延迟初始化、日志记录、或网络访问等。适用场景远程代理:为一个对象在不同......
  • 使用 LCM 加速生图
    LCM是什么在人工智能领域,图像生成技术一直是研究的热点。然而,尽管取得了显著进展,现有技术如StableDiffusion等在生成高质量图像时仍面临速度瓶颈。多步迭代采样过程不仅耗时,而且增加了推理成本,限制了这些技术在实时应用场景中的潜力。为了解决上述问题,清华大学交叉信息研究......
  • 要将 Python 脚本制作成可执行程序,您可以使用以下几种方法:
    要将Python脚本制作成可执行程序,您可以使用以下几种方法:1.使用PyInstallerPyInstaller是一个非常流行的工具,可以将Python脚本打包成独立的可执行文件,支持Windows、macOS和Linux。您可以按照以下步骤进行操作:安装PyInstaller:复制代码pipinstallpyinstaller......
  • PLM是什么?一文读懂PLM系统的定位、价值、特点、功能(流程行业&离散行业)、实施、以及发
    随着全球制造业向智能化、数字化转型,产品生命周期管理(PLM)系统已成为企业优化研发流程、加速产品上市速度的关键工具。本文将带您深入了解PLM,了解研发管理的最佳实践。01、PLM系统的定位PLM即产品生命周期管理,ProductLifecycleManagement的简称。PLM系统包括三个方面的意涵:......
  • 【C语言学习】2.常量的分类及使用
    C语言中的常量有以下几种:·字面常量·const修饰的常变量·#define定义的标识符常量·枚举常量1.字面常量如数字(整型、浮点型),字符串等2.const修饰的常变量对于a这一变量,可以多次赋值而使用const修饰后变量被锁定,变更为常变量仍为变量的证明:创建数组后运行,报错显示其......