joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

在 Vue.js 项目中使用 xlsx-js-style 来将 HTML 表格转换为 Excel 并下载,可以通过以下步骤实现:

步骤

  1. 安装 xlsx-js-style 库:
    使用 npm 安装 xlsx-js-style 库。

    npm install xlsx-js-style
    
  2. 创建 Vue 组件:
    创建一个 Vue 组件,在其中实现表格到 Excel 的转换和下载。

示例代码

<template>
  <div>
    <table id="myTable">
      <thead>
        <tr>
          <th>Header 1</th>
          <th>Header 2</th>
          <th>Header 3</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data 1</td>
          <td>Data 2</td>
          <td>Data 3</td>
        </tr>
        <tr>
          <td>Data 4</td>
          <td>Data 5</td>
          <td>Data 6</td>
        </tr>
      </tbody>
    </table>
    <button @click="downloadExcel">Download as Excel</button>
  </div>
</template>

<script>
import * as XLSX from 'xlsx-js-style';

export default {
  name: 'TableToExcel',
  methods: {
    downloadExcel() {
      // 获取表格元素
      const table = document.getElementById('myTable');

      // 将表格转换为工作簿
      const wb = XLSX.utils.table_to_book(table, { sheet: 'Sheet JS' });

      // 获取工作表
      const ws = wb.Sheets['Sheet JS'];
      const range = XLSX.utils.decode_range(ws['!ref']);

      // 遍历单元格并添加样式
      for (let R = range.s.r; R <= range.e.r; ++R) {
        for (let C = range.s.c; C <= range.e.c; ++C) {
          const cell_address = { c: C, r: R };
          const cell_ref = XLSX.utils.encode_cell(cell_address);

          if (!ws[cell_ref]) continue;

          // 样式示例
          ws[cell_ref].s = {
            fill: { fgColor: { rgb: 'FFFFAA00' } },
            font: { name: 'Arial', sz: 14, bold: true, color: { rgb: 'FF000000' } },
            alignment: { horizontal: 'center', vertical: 'center' },
          };
        }
      }

      // 导出 Excel 文件
      XLSX.writeFile(wb, 'table.xlsx');
    },
  },
};
</script>

<style>
/* 你的样式 */
</style>

详细说明:

  1. 安装依赖:

    • 使用 npm install xlsx-js-style 安装 xlsx-js-style 库。
  2. 组件模板:

    • 定义一个表格和一个按钮,按钮绑定 downloadExcel 方法。
  3. 脚本部分:

    • 导入 xlsx-js-style 库。
    • 定义 downloadExcel 方法。
      • 获取表格元素。
      • 使用 XLSX.utils.table_to_book 方法将表格转换为工作簿。
      • 获取工作表并遍历单元格,应用样式。
      • 使用 XLSX.writeFile 方法将工作簿导出为 Excel 文件。
  4. 样式部分:

    • 你可以根据需要添加自定义样式。

扩展功能:

  • 根据需要,可以扩展 downloadExcel 方法以支持更多样式和功能。
  • 可以动态生成表格内容,并使用 Vue 的数据绑定来管理表格数据。

这个示例展示了如何在 Vue 中使用 xlsx-js-style 将 HTML 表格转换为带样式的 Excel 文件并下载。如果你需要进一步的自定义或优化,可以根据需求进行调整。

添加多个工作表sheet

在 Vue.js 中使用 xlsx-js-style 添加多张工作表,并将 HTML 表格转换为 Excel 文件下载,可以按照以下步骤进行。以下是一个示例,演示如何将多个 HTML 表格分别添加到不同的工作表中,并下载包含这些工作表的 Excel 文件。

步骤

  1. 安装 xlsx-js-style 库:
    使用 npm 安装 xlsx-js-style 库。

    npm install xlsx-js-style
    
  2. 创建 Vue 组件:
    创建一个 Vue 组件,在其中实现将多个表格添加到不同工作表并下载的功能。

示例代码

<template>
  <div>
    <table id="table1">
      <thead>
        <tr>
          <th>Table 1 Header 1</th>
          <th>Table 1 Header 2</th>
          <th>Table 1 Header 3</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data 1</td>
          <td>Data 2</td>
          <td>Data 3</td>
        </tr>
        <tr>
          <td>Data 4</td>
          <td>Data 5</td>
          <td>Data 6</td>
        </tr>
      </tbody>
    </table>
    <table id="table2">
      <thead>
        <tr>
          <th>Table 2 Header 1</th>
          <th>Table 2 Header 2</th>
          <th>Table 2 Header 3</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data A</td>
          <td>Data B</td>
          <td>Data C</td>
        </tr>
        <tr>
          <td>Data D</td>
          <td>Data E</td>
          <td>Data F</td>
        </tr>
      </tbody>
    </table>
    <button @click="downloadExcel">Download as Excel</button>
  </div>
</template>

<script>
import * as XLSX from 'xlsx-js-style';

export default {
  name: 'TableToExcel',
  methods: {
    downloadExcel() {
      // 创建一个新的工作簿
      const wb = XLSX.utils.book_new();

      // 将第一个表格转换为工作表并添加到工作簿
      const table1 = document.getElementById('table1');
      const ws1 = XLSX.utils.table_to_sheet(table1);
      this.applyStyles(ws1);
      XLSX.utils.book_append_sheet(wb, ws1, 'Sheet1');

      // 将第二个表格转换为工作表并添加到工作簿
      const table2 = document.getElementById('table2');
      const ws2 = XLSX.utils.table_to_sheet(table2);
      this.applyStyles(ws2);
      XLSX.utils.book_append_sheet(wb, ws2, 'Sheet2');

      // 导出 Excel 文件
      XLSX.writeFile(wb, 'tables.xlsx');
    },
    applyStyles(ws) {
      const range = XLSX.utils.decode_range(ws['!ref']);
      for (let R = range.s.r; R <= range.e.r; ++R) {
        for (let C = range.s.c; C <= range.e.c; ++C) {
          const cell_address = { c: C, r: R };
          const cell_ref = XLSX.utils.encode_cell(cell_address);

          if (!ws[cell_ref]) continue;

          // 样式示例
          ws[cell_ref].s = {
            fill: { fgColor: { rgb: 'FFFFAA00' } },
            font: { name: 'Arial', sz: 14, bold: true, color: { rgb: 'FF000000' } },
            alignment: { horizontal: 'center', vertical: 'center' },
          };
        }
      }
    }
  }
};
</script>

<style>
/* 你的样式 */
</style>

详细说明:

  1. 安装依赖:

    • 使用 npm install xlsx-js-style 安装 xlsx-js-style 库。
  2. 组件模板:

    • 定义两个表格和一个按钮,按钮绑定 downloadExcel 方法。
  3. 脚本部分:

    • 导入 xlsx-js-style 库。
    • 定义 downloadExcel 方法:
      • 创建一个新的工作簿 wb
      • 获取第一个表格元素,并将其转换为工作表 ws1,应用样式后添加到工作簿中。
      • 获取第二个表格元素,并将其转换为工作表 ws2,应用样式后添加到工作簿中。
      • 使用 XLSX.writeFile 方法将工作簿导出为 Excel 文件。
    • 定义 applyStyles 方法:
      • 遍历工作表的单元格,并为每个单元格应用样式。
  4. 样式部分:

    • 根据需要添加自定义样式。

扩展功能:

  • 根据需要,可以扩展 downloadExcel 方法以支持更多的表格和工作表。
  • 可以动态生成表格内容,并使用 Vue 的数据绑定来管理表格数据。

通过这个示例代码,你可以将多个 HTML 表格分别添加到不同的工作表中,并下载包含这些工作表的 Excel 文件。如果需要进一步自定义或优化,可以根据需求进行调整。

使用案例代码

封装常用的表格导出方法

import { isArray } from 'lodash-es';
import XLSX from 'xlsx-js-style';
// columns:表头数据   data:表格数据    excelName:导出的文件名    autoWidth: 自适应列宽  sheetTitle:sheet名称,excel打开以后,的底部切换名称 wrapText:是否自动换行
export interface exportExcelTypes {
  columns: any[]
  data: any[]
  excelName?: string
  autoWidth?: boolean
  sheetTitle?: string
  wrapText?: ''
}
// 导出表头默认样式
const THeaderStyle = {
  // font 字体属性
  font: {
      bold: true,
      sz: 12
  },
  // alignment 对齐方式
  alignment: {
      vertical: 'center', // 垂直居中
      horizontal: 'center', // 水平居中
  },
  // fill 颜色填充属性
  fill: {
      fgColor: { rgb: 'e1e2e3' },
  },
  // border style
  border: {
      top: { style: 'thin', color: { rgb: '909399' } },
      right: { style: 'thin', color: { rgb: '909399' } },
      bottom: { style: 'thin', color: { rgb: '909399' } },
      left: { style: 'thin', color: { rgb: '909399' } }
  }
}
const TBodyStyle = {
  alignment: {// 文字居中 //字体水平居中、垂直居中、自动换行
      font: {// 字体设置
          sz: 12,
          bold: false,
      },
      horizontal: 'left', //居中
      vertical: 'center', //垂直居中
      wrapText: true
  },
  // numFmt:'@'
}
/**
* 自适应列宽
* @param {*} data
* @returns {*}  {*}
*/
const autoWidthFn = (data: any): any => {
  // 设置worksheet每列的最大宽度
  const colWidth = data.map((row: any) => row.map((val: { toString: () => { (): any; new(): any; charCodeAt: { (arg0: number): number; new(): any; }; length: number; }; } | null) => {
      // 先判断是否为null/undefined
      if (val == null) {
          return {
              'width': 10
          }
      }
      // 再判断是否为中文
      else if (val.toString().charCodeAt(0) > 255) {
          return {
              'width': val.toString().length * 2 + 6
          }
      } else {
          return {
              'width': val.toString().length + 2 + 1
          }
      }
  }))
  // 以第一行为初始值
  const result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
          if (result[j]['width'] < colWidth[i][j]['width']) {
              result[j]['width'] = colWidth[i][j]['width'] > 480 ? 480 : colWidth[i][j]['width']
          }
      }
  }
  return result
}
/**
* 是否自动换行
* @param {*} sheet
* @returns {*}  {*}
*/
const wrapTextFn = (sheet: any): any => {
  for (const key in sheet) {
      if (key.indexOf('!') === -1) { // 排除带!的字段,只要单元格字段
          if (!sheet[key].s && sheet[key].z != 'm/d/yy') {
              sheet[key].t = 's'
              sheet[key].s = TBodyStyle
          }
      }
  }
  return sheet
}
/**
* json数据导出excel
* @param {exportExcelTypes} params
*/
export const exportExcel = (params: exportExcelTypes) => {
  const { columns, data, excelName, autoWidth = true, sheetTitle = 'sheet名称', wrapText = false } = params
  if (!isArray(columns) || !isArray(data)) {
      return
  }
  const THeader: any = [], filterVal: any = [];
  columns.forEach((item: { label: any; prop: any; }) => {
      THeader.push({
          v: item.label,
          t: 's',
          s: THeaderStyle
      })
      filterVal.push(item.prop)
  })
  const TData = data.map(v => filterVal.map((j: string | number) => v[j]))
  const sheetData = [[...THeader], ...TData]
  const sheet = XLSX.utils.aoa_to_sheet(sheetData);// aoa_to_sheet 将二维数组转成 sheet
  // 自适应列宽
  if (autoWidth) { sheet['!cols'] = autoWidthFn(sheetData) }
  // 自动换行
  if (wrapText) { wrapTextFn(sheet) }
  // 设置表头行高
  const rows = [{ hpx: 20 }]
  sheet['!rows'] = rows; // 将rows添加到sheet中,设置行高
  // 创建虚拟的 workbook
  const workbook = XLSX.utils.book_new();
  // 向 workbook 中添加 sheet
  XLSX.utils.book_append_sheet(workbook, sheet, sheetTitle);
  // 导出 workbook
  XLSX.writeFile(workbook, ${excelName ? (excelName.includes('.xlsx') ? excelName : excelName + '.xlsx') : 'excel名称.xlsx'});
}
/**
* json数据导出excel 导出多个
* @param {{ params: exportExcelTypes[], excelName: string }} dataParams
* @returns 
*/
export const exportMultipleExcel = (dataParams: { params: exportExcelTypes[], excelName: string }) => {
  const { params, excelName } = dataParams
  if (!isArray(params)) {
      return
  }
  // 创建虚拟的 workbook
  const workbook = XLSX.utils.book_new();
  params.forEach((item: any) => {
      const { columns, data, autoWidth = true, sheetTitle = 'sheet名称', wrapText = false } = item
      if (!isArray(columns) || !isArray(data)) {
          return
      }
      const THeader: any = [], filterVal: any = [];
      columns.forEach((item: { label: any; prop: any; }) => {
          THeader.push({
              v: item.label,
              t: 's',
              s: THeaderStyle
          })
          filterVal.push(item.prop)
      })
      const TData = data.map(v => filterVal.map((j: string | number) => v[j]))
      const sheetData = [[...THeader], ...TData]
      const sheet = XLSX.utils.aoa_to_sheet(sheetData);// aoa_to_sheet 将二维数组转成 sheet
      // 自适应列宽
      if (autoWidth) { sheet['!cols'] = autoWidthFn(sheetData) }
      // 自动换行
      if (wrapText) { wrapTextFn(sheet) }
      // 设置表头行高
      const rows = [{ hpx: 20 }]
      sheet['!rows'] = rows; // 将rows添加到sheet中,设置行高
      // 向 workbook 中添加 sheet
      XLSX.utils.book_append_sheet(workbook, sheet, sheetTitle);
  })
  // 导出 workbook
  XLSX.writeFile(workbook, ${excelName ? (excelName.includes('.xlsx') ? excelName : excelName + '.xlsx') : 'excel名称.xlsx'});
}
/**
* 使用插件内的方法,自动使用dom转换为数据
* 通过将一个table dom直接转成sheet,会自动识别colspan和rowspan并将其转成对应的单元格合并
* @param {{ id: string, excelName: string, autoWidth: boolean, sheetTitle: string, wrapText: boolean}} dataParams
* @returns 
*/
export const exportDomExcel = (dataParams: { id: string, excelName: string, autoWidth: boolean, sheetTitle: string, wrapText?: boolean }) => {
  const { id, excelName, autoWidth = true, sheetTitle = 'sheet名称', wrapText = false } = dataParams
  const table = document.querySelector(id);
  // Generate the sheet data and add styles:
  const sheet = XLSX.utils.table_to_sheet(table); //将一个table对象转换成一个sheet对象
  const headerRange = XLSX.utils.decode_range(sheet['!ref']);
  // 把table sheet对象转换成二进制数据
  const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
  const arrayData: any = [];
  jsonData.forEach((row: any) => {
      const rowData: any = [];
      Object.values(row).forEach((cell) => {
          rowData.push(cell);
      });
      arrayData.push(rowData);
  });
  // 设置表头样式
  for (let col = headerRange.s.c; col <= headerRange.e.c; col++) {
      const cellInfo = XLSX.utils.encode_cell({ r: 0, c: col });
      const cell = sheet[cellInfo];
      cell.s = THeaderStyle;
  }
  // 自适应列宽
  if (autoWidth) {
      sheet['!cols'] = autoWidthFn(arrayData)
  }
  // 自动换行
  if (wrapText) { wrapTextFn(sheet) }
  // 设置表头行高
  const rows = [{ hpx: 20 }]
  sheet['!rows'] = rows; // 将rows添加到sheet中,设置行高
  // 创建虚拟的 workbook
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, sheet, sheetTitle);
  XLSX.writeFile(workbook, ${excelName ? (excelName.includes('.xlsx') ? excelName : excelName + '.xlsx') : 'excel名称.xlsx'});
  return
}
/**
* 手动把table内的值,获取到组装成所需要的数组 如果不需要过滤下载的表格列,用第一个更好,这个主要是为了过滤列,报告里需要过滤掉需要跟操作两列
* 通过将一个table dom直接转成sheet,会自动识别colspan和rowspan并将其转成对应的单元格合并
* @param {{ id: string, excelName: string, autoWidth: boolean, sheetTitle: string, wrapText: boolean,filterTHeaderTextArr:string[]}} dataParams
* @returns 
*/
export const exportDomExcelFilter = (dataParams: { id: string, excelName: string, autoWidth: boolean, sheetTitle: string, wrapText?: boolean, filterTHeaderTextArr?: string[] }) => {
  const { id, excelName, autoWidth = true, sheetTitle = 'sheet名称', wrapText = false, filterTHeaderTextArr = [] } = dataParams
  const table: any = document.querySelector(id);
  // Generate the sheet data and add styles:
  const rows = Array.from(table.getElementsByTagName('tr'));
  const tableData = rows.map((row: any) => Array.from(row.getElementsByTagName('td')).map((cell: any) => cell.textContent.trim())).filter(item => item.length > 0);
  const THeader = rows.map((row: any) => Array.from(row.getElementsByTagName('th')).map((cell: any) => cell.textContent.trim())).filter(item => item.length > 0);
  if (THeader.length) {
      THeader.forEach((item: any) => {
          item.forEach((it: any, ind: number) => {
              if (filterTHeaderTextArr.includes(it)) {
                  item.splice(ind, 1)
                  tableData.forEach(datas => {
                      datas.splice(ind, 1)
                  })
              }
          })
      })
  }
  const sheetData = [...THeader, ...tableData]
  const sheet = XLSX.utils.aoa_to_sheet(sheetData);// aoa_to_sheet 将二维数组转成 sheet
  const headerRange = XLSX.utils.decode_range(sheet['!ref']);
  // 设置表头样式
  for (let col = headerRange.s.c; col <= headerRange.e.c; col++) {
      const cellInfo = XLSX.utils.encode_cell({ r: 0, c: col });
      const cell = sheet[cellInfo];
      cell.s = THeaderStyle;
  }
  // 自适应列宽
  if (autoWidth) { sheet['!cols'] = autoWidthFn(sheetData) }
  // 自动换行
  if (wrapText) { wrapTextFn(sheet) }
  // 设置表头行高
  const rowstyle = [{ hpx: 20 }]
  sheet['!rows'] = rowstyle; // 将rows添加到sheet中,设置行高
  // 创建虚拟的 workbook
  const workbook = XLSX.utils.book_new();
  // 向 workbook 中添加 sheet
  XLSX.utils.book_append_sheet(workbook, sheet, sheetTitle);
  // 导出 workbook
  XLSX.writeFile(workbook, ${excelName ? (excelName.includes('.xlsx') ? excelName : excelName + '.xlsx') : 'excel名称.xlsx'});
}

更多参考文章

https://www.jiafeng.fun/details/409

posted on   joken1310  阅读(135)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示