vue3集成excel表格展示

<template>
  <div>
    <!-- 表格展示 -->
    <div class="table-container">
      <div v-if="!tableData.length">数据加载中...</div>
      <table v-else class="excel-table">
        <thead>
          <tr>
            <th
              v-for="(header, colIndex) in tableHeaders"
              :key="colIndex"
              :rowspan="getHeaderRowspan(0, colIndex)"
              :colspan="getHeaderColspan(0, colIndex)"
              v-show="!isCellHidden(0, colIndex)"
            >
              {{ header }}
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(row, rowIndex) in tableBody" :key="rowIndex">
            <td
              v-for="(cell, colIndex) in row"
              :key="colIndex"
              :rowspan="getCellRowspan(rowIndex + 1, colIndex)"
              :colspan="getCellColspan(rowIndex + 1, colIndex)"
              :class="{ 'merged-cell': isMergedCell(rowIndex + 1, colIndex) }"
              v-show="!isCellHidden(rowIndex + 1, colIndex)"
            >
              {{ cell }}
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script setup>
import axios from "axios";
import * as XLSX from "xlsx";

const tableData = ref([]);
const tableHeaders = ref([]);
const mergeInfo = ref([]); // 存储合并单元格信息
const cellStyles = ref({}); // 存储单元格样式信息

// 获取表格主体数据(排除表头)
const tableBody = computed(() => {
  return tableData.value.slice(1);
});

// 检查单元格是否被隐藏(在合并区域中但不是起始单元格)
const isCellHidden = (rowIndex, colIndex) => {
  for (const merge of mergeInfo.value) {
    if (rowIndex >= merge.startRow && rowIndex <= merge.endRow && colIndex >= merge.startCol && colIndex <= merge.endCol) {
      // 如果是合并区域的起始单元格,不隐藏
      if (rowIndex === merge.startRow && colIndex === merge.startCol) {
        return false;
      }
      // 其他合并区域的单元格需要隐藏
      return true;
    }
  }
  return false;
};

// 获取单元格的 rowspan
const getCellRowspan = (rowIndex, colIndex) => {
  for (const merge of mergeInfo.value) {
    if (rowIndex === merge.startRow && colIndex === merge.startCol) {
      return merge.endRow - merge.startRow + 1;
    }
  }
  return 1;
};

// 获取单元格的 colspan
const getCellColspan = (rowIndex, colIndex) => {
  for (const merge of mergeInfo.value) {
    if (rowIndex === merge.startRow && colIndex === merge.startCol) {
      return merge.endCol - merge.startCol + 1;
    }
  }
  return 1;
};

// 获取表头的 rowspan
const getHeaderRowspan = (rowIndex, colIndex) => {
  for (const merge of mergeInfo.value) {
    if (rowIndex === merge.startRow && colIndex === merge.startCol) {
      return merge.endRow - merge.startRow + 1;
    }
  }
  return 1;
};

// 获取表头的 colspan
const getHeaderColspan = (rowIndex, colIndex) => {
  for (const merge of mergeInfo.value) {
    if (rowIndex === merge.startRow && colIndex === merge.startCol) {
      return merge.endCol - merge.startCol + 1;
    }
  }
  return 1;
};

// 检查是否为合并单元格的起始位置
const isMergedCell = (rowIndex, colIndex) => {
  for (const merge of mergeInfo.value) {
    if (rowIndex === merge.startRow && colIndex === merge.startCol) {
      return true;
    }
  }
  return false;
};

// 处理文件选择
const loadProjectExcel = async () => {
  try {
    const response = await axios.get("/park.xlsx", { responseType: "arraybuffer" });
    const data = new Uint8Array(response.data);
    const workbook = XLSX.read(data, { type: "array" });
    const firstSheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[firstSheetName];

    // 获取合并单元格信息
    if (worksheet["!merges"]) {
      mergeInfo.value = worksheet["!merges"].map(merge => ({
        startRow: merge.s.r,
        startCol: merge.s.c,
        endRow: merge.e.r,
        endCol: merge.e.c,
      }));
    } else {
      mergeInfo.value = [];
    }

    // 转换工作表数据
    const jsonData = XLSX.utils.sheet_to_json(worksheet, {
      header: 1,
      defval: "", // 为空单元格提供默认值
    });

    // 处理数据
    if (jsonData.length > 0) {
      tableHeaders.value = jsonData[0] || [];
      tableData.value = jsonData;
    }
  } catch (error) {
    console.error("处理 Excel 文件时出错:", error);
  }
};
onMounted(() => {
  loadProjectExcel();
});
</script>

<style scoped>
.table-container {
  overflow-x: auto;
  margin-top: 20px;
  min-height: 500px;
}

.excel-table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid #ddd;
}

.excel-table th,
.excel-table td {
  border: 1px solid #ddd;
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
}

.excel-table th {
  background-color: #f5f5f5;
  font-weight: bold;
}

.excel-table tr:nth-child(even) {
  background-color: #f9f9f9;
}

.excel-table tr:hover {
  background-color: #f0f0f0;
}

.merged-cell {
  /* background-color: #e8f4fd; */
  text-align: center;
}
</style>

图片说明文字