joken-前端工程师

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::

测试代码

<template>
  <div class='box'>
    demo
    <el-button type="primary" @click="exportImageToExcel">test</el-button>
  </div>
</template>

<script lang='ts' setup>
import { ref } from 'vue';
import ExcelJS from 'exceljs';
import type { Anchor } from 'exceljs';
import { baseImg } from "./ts/basePic";

// Constants
const MM_EMU_RATIO = 10000;  // 点到 emu 单位的转换
const PX_DOT_RATIO = 0.75;   // px 到点的转换
const CHAR_DOT_RATIO = 5.25; // 字符到点的转换

// Convert px to dots
function pxToDots(px: number): number {
  return px * PX_DOT_RATIO;
}

// Convert dots to character width
function dotsToCharWidth(dots: number): number {
  return dots / CHAR_DOT_RATIO;
}

// Setup worksheet columns and rows
function setupWorksheetDimensions(worksheet: ExcelJS.Worksheet, picWidthDots: number, picHeightDots: number) {
  const charWidth = dotsToCharWidth(picWidthDots) + 20; // Width in character units
  worksheet.getColumn(2).width = charWidth;
  worksheet.getColumn(3).width = charWidth;
  worksheet.getRow(2).height = picHeightDots + 100; // Row height
  worksheet.mergeCells('B2:D2');
}

// Calculate image offset
function calculateImageOffset(worksheet: ExcelJS.Worksheet, picWidthDots: number, picHeightDots: number) {
  const mergedWidth = (worksheet.getColumn(2).width as number) * 2 + (worksheet.getColumn(3).width as number);
  const rowHeight = worksheet.getRow(2).height as number;
  const marginTop = ((rowHeight * 1.3) - picHeightDots) / 2;
  const marginLeft = ((mergedWidth * 1.48 * CHAR_DOT_RATIO - picWidthDots) / 2);
  return {
    topOffset: Math.floor(marginTop * MM_EMU_RATIO),
    leftOffset: Math.floor(marginLeft * MM_EMU_RATIO),
  };
}

// Add image to worksheet
function addImageToWorksheet(workbook: ExcelJS.Workbook, worksheet: ExcelJS.Worksheet, picWidthDots: number, picHeightDots: number) {
  const imageId = workbook.addImage({
    extension: 'png',
    base64: baseImg,
  });

  const { topOffset, leftOffset } = calculateImageOffset(worksheet, picWidthDots, picHeightDots);
  // 核心居中方式就是这个设置了
  const imgSets = {
    tl: { nativeRow: 1, nativeCol: 1, nativeRowOff: topOffset, nativeColOff: leftOffset } as Anchor, 
    ext: { width: picWidthDots, height: picHeightDots },
    editAs: 'oneCell',
  };

  worksheet.addImage(imageId, imgSets);
}

// Download Excel file
async function downloadExcelFile(workbook: ExcelJS.Workbook, fileName: string) {
  const buffer = await workbook.xlsx.writeBuffer();
  const blob = new Blob([buffer], { type: 'application/octet-stream' });
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = fileName;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  window.URL.revokeObjectURL(url);
}

// Main export function
async function exportImageToExcel() {
  const workbook = new ExcelJS.Workbook();
  const worksheet = workbook.addWorksheet('Images');
  const picWidth = pxToDots(100);  // Width in dots
  const picHeight = pxToDots(100); // Height in dots

  setupWorksheetDimensions(worksheet, picWidth, picHeight);
  addImageToWorksheet(workbook, worksheet, picWidth, picHeight);
  await downloadExcelFile(workbook, 'output.xlsx');
}

</script>

<style lang='scss' scoped>
.box {
  padding: 16px;
}
</style>

  • 效果
    image
    刚好居中
    垮了3个单元格,宽度都太一样的单元格

核心实现

 const imgSets = {
    tl: { nativeRow: 1, nativeCol: 1, nativeRowOff: topOffset, nativeColOff: leftOffset } as Anchor, 
    ext: { width: picWidthDots, height: picHeightDots },
    editAs: 'oneCell',
  };

  worksheet.addImage(imageId, imgSets);
  

Anchor 参数参考
image

  • 部分参数解释
    tl 是top left 起始点设置
    nativeRow 是行位置,只能是正整数
    nativeCol 是列位置,只能是正整数
    nativeRowOff 是行偏移量,不受单元格限制,可以是正数也可以是负数,最好传入整数,单位是EMU,1点等于10000emu,excel的单位是点,1px约等于0.75个点,这是网页的转换单位
    nativeColOff 是列偏移量,同nativeRowOff
    ext 用来设置图片宽度高度
    width 图片宽度,单位点
    height 图片宽度,单位点

editAs 是用来设置生成后的图片被单元格的移动的影响方式,和这里我们的定位无关,可以不用设置

单位转换解释

  1. MM_EMU_RATIO = 10000

    • 解释:这是点(EMU 单位)到 Excel 所用的 EMU 单位(英语单位 - 英寸的 1/914400)的转换比率。EMU(English Metric Unit)是 Excel 中用于图形和图片定位的内部单位,1 点约等于 10000 EMU。
    • 用途:用于将点单位转换为 EMU,以精确控制图片在 Excel 中的定位偏移(如 nativeRowOffnativeColOff)。
  2. PX_DOT_RATIO = 0.75

    • 解释:这是 px(像素)到点的转换比率。一般情况下,1 px 约等于 0.75 点(点是字体大小和距离的传统度量单位,1 英寸为 72 点)。
    • 用途:用于将像素值转换为点单位,以便统一尺寸单位,例如将图片的像素宽度或高度转换为 Excel 的点单位。
  3. CHAR_DOT_RATIO = 5.25

    • 解释:这是字符宽度到点的转换比率。在 Excel 中,列宽通常以字符宽度来表示,CHAR_DOT_RATIO 约定了字符宽度和点之间的关系,1 字符宽度约等于 5.25 点。
    • 用途:将点数转换为字符单位,以便根据 Excel 的列宽设置需求调整宽度,使之与字符数对齐。

这些转换比率允许将尺寸从 px 和字符单位转换到 Excel 内部使用的点或 EMU 单位,实现对图片和表格单元格尺寸的更精确控制。

posted on 2024-11-05 22:13  joken1310  阅读(25)  评论(0编辑  收藏  举报