Virtualized Table 虚拟化表格 el-table-v2 表头分组 多级表头的简单示例

注意添加这个属性,会影响到有多少个层级的表头: :header-height=“[50, 40]”,即后面的columnIndex

如果有fix的列CustomizedHeader会被调用多次,如果有多个层级的表头,也会被调用多次, 实际被调用次数是(fix数+ 1 * 表头层级数量)

以下代码均删除了JSX

TS版本代码

<template>
  <div  style="width: 100%;height: calc(100vh - 84px)">
    <el-auto-resizer>
      <template #default="{ height, width }">
        <el-table-v2
            fixed
            :columns="columns"
            :data="data"
            :sort-by="sortBy"
            :header-height="[50, 40]"
            :header-class="headerClass"
            @column-sort="onSort"
            :width="width"
            :height="height"
        >
          <template #header="props">
            <customized-header v-bind="props"></customized-header>
          </template>
        </el-table-v2>
      </template>
    </el-auto-resizer>
  </div>
</template>

<script lang="ts" setup>
import {h, ref} from 'vue'
import {TableV2FixedDir, TableV2Placeholder, TableV2SortOrder} from 'element-plus'
import type {
  HeaderClassNameGetter,
  TableV2CustomizedHeaderSlotParam,
} from 'element-plus'
import type {SortBy} from 'element-plus'



// 生成带二级表头的 columns
function generateColumns(length = 10, prefix = 'column-', props?: any) {
  return Array.from({length}).map((_, columnIndex) => ({
    ...props,
    key: `${prefix}${columnIndex}`,
    dataKey: `${prefix}${columnIndex}`,
    title: `Column ${columnIndex}`,
    width: 150,
  }))
}

function generateData(
    columns: ReturnType<typeof generateColumns>,
    length = 200,
    prefix = 'row-'
) {
  return Array.from({ length }).map((_, rowIndex) => {
    return columns.reduce(
        (rowData, column, columnIndex) => {
          rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
          return rowData
        },
        {
          id: `${prefix}${rowIndex}`,
          parentId: null,
        }
    )
  })
}

function CustomizedHeader({cells, columns, headerIndex}) {
  if (headerIndex === 1) return cells

  const groupCells = []
  let width = 0
  let idx = 0

  columns.forEach((column, columnIndex) => {
    if (column.placeholderSign === TableV2Placeholder) {
      groupCells.push(cells[columnIndex])
    } else {
      width += cells[columnIndex].props.column.width
      idx++

      const nextColumn = columns[columnIndex + 1]
      if (
          columnIndex === columns.length - 1 ||
          nextColumn?.placeholderSign === TableV2Placeholder ||
          idx === (headerIndex === 0 ? 4 : 2)
      ) {
        groupCells.push(
            h(
                'div',
                {
                  class: 'flex items-center justify-center custom-header-cell',
                  role: 'columnheader',
                  style: {
                    ...cells[columnIndex].props.style,
                    width: `${width}px`,
                    border: `2px solid #fff`
                  }
                },
                `Group width ${width}`
            )
        )
        width = 0
        idx = 0
      }
    }
  })
  return groupCells;
}


const headerClass = ({
                       headerIndex,
                     }: Parameters<HeaderClassNameGetter<any>>[0]) => {
  if (headerIndex === 0) return 'el-primary-color'
  return ''
}

const columns = generateColumns(70)
let data = generateData(columns, 20)

columns[0].fixed = TableV2FixedDir.LEFT

for (let i = 0; i < 3; i++) columns[i].sortable = true

const sortBy = ref<SortBy>({
  key: 'column-0',
  order: TableV2SortOrder.ASC,
})

const onSort = (_sortBy: SortBy) => {
  data = data.reverse()
  sortBy.value = _sortBy
}
</script>

<style>
.el-el-table-v2__header-row .custom-header-cell {
  border-right: 1px solid var(--el-border-color);
}

.el-el-table-v2__header-row .custom-header-cell:last-child {
  border-right: none;
}

.el-primary-color {
  background-color: var(--el-color-primary);
  color: var(--el-color-white);
  font-size: 14px;
  font-weight: bold;
}

.el-primary-color .custom-header-cell {
  padding: 0 4px;
}
</style>

JS版本

<template>
  <div style="width: 100%;height: calc(100vh - 84px)">
    <el-auto-resizer>
      <template #default="{ height, width }">
        <el-table-v2
            fixed
            :columns="columns"
            :data="data"
            :sort-by="sortBy"
            :header-height="[50, 40]"
            :header-class="headerClass"
            @column-sort="onSort"
            :width="width"
            :height="height"
        >
          <template #header="props">
            <CustomizedHeader v-bind="props"></CustomizedHeader>
          </template>
        </el-table-v2>
      </template>
    </el-auto-resizer>
  </div>
</template>

<script setup>
import { h, ref } from 'vue'
import {
  TableV2FixedDir,
  TableV2Placeholder,
  TableV2SortOrder
} from 'element-plus'

// 生成带二级表头的 columns
function generateColumns(length = 10, prefix = 'column-') {
  return Array.from({ length }).map((_, columnIndex) => ({
    key: `${prefix}${columnIndex}`,
    dataKey: `${prefix}${columnIndex}`,
    title: `Column ${columnIndex}`,
    width: 150
  }))
}

function generateData(columns, length = 200, prefix = 'row-') {
  return Array.from({ length }).map((_, rowIndex) => {
    return columns.reduce(
        (rowData, column, columnIndex) => {
          rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
          return rowData
        },
        {
          id: `${prefix}${rowIndex}`,
          parentId: null
        }
    )
  })
}

function CustomizedHeader({ cells, columns, headerIndex }) {
  if (headerIndex === 1) return cells

  const groupCells = []
  let width = 0
  let idx = 0

  columns.forEach((column, columnIndex) => {
    if (column.placeholderSign === TableV2Placeholder) {
      groupCells.push(cells[columnIndex])
    } else {
      width += cells[columnIndex].props.column.width
      idx++

      const nextColumn = columns[columnIndex + 1]
      if (
          columnIndex === columns.length - 1 ||
          nextColumn?.placeholderSign === TableV2Placeholder ||
          idx === (headerIndex === 0 ? 4 : 2)
      ) {
        groupCells.push(
            h(
                'div',
                {
                  class: 'flex items-center justify-center custom-header-cell',
                  role: 'columnheader',
                  style: {
                    ...cells[columnIndex].props.style,
                    width: `${width}px`,
                    border: `2px solid #fff`
                  }
                },
                `Group width ${width}`
            )
        )
        width = 0
        idx = 0
      }
    }
  })
  return groupCells
}


const headerClass = ({ headerIndex }) => {
  return headerIndex === 0 ? 'el-primary-color' : ''
}

const columns = generateColumns(70)
let data = generateData(columns, 20)

columns[0].fixed = TableV2FixedDir.LEFT

for (let i = 0; i < 3; i++) {
  columns[i].sortable = true
}

const sortBy = ref({
  key: 'column-0',
  order: TableV2SortOrder.ASC
})

const onSort = (_sortBy) => {
  // 创建新数组以保持响应性
  data = [...data].reverse()
  sortBy.value = _sortBy
}

</script>

<style>
.el-el-table-v2__header-row .custom-header-cell {
  border-right: 1px solid var(--el-border-color);
}

.el-el-table-v2__header-row .custom-header-cell:last-child {
  border-right: none;
}

.el-primary-color {
  background-color: var(--el-color-primary);
  color: var(--el-color-white);
  font-size: 14px;
  font-weight: bold;
}

.el-primary-color .custom-header-cell {
  padding: 0 4px;
}
</style>
Element UI Plus中的Virtualized Table(虚拟滚动表格)是通过数据分块加载的方式提高大表格性能的组件。为了将其导出为Excel文件,你可以采用以下步骤: 1. **收集完整数据**:首先,你需要确保表格的所有数据都被加载到内存中,因为虚拟化表实际上只显示了一部分数据。这可能需要你在导出前一次性获取所有行数据。 2. **数据转换**:使用JavaScript库,比如`xlsx`(Node.js中的Excel文件生成库),将整个表格数据转成Excel所需的二维数组或工作簿对象。 3. **利用`xlsx`创建工作簿**:安装并引入`xlsx`库后,你可以创建一个新的工作簿对象,并添加一个工作表。然后,将数据逐行写入该工作表中。 4. **导出到文件**:使用`xlsx.writeFile`方法,将工作簿对象写入到`.xlsx`文件中。 ```javascript const XLSX = require('xlsx'); // 假设表格数据已经保存在data变量中 const workbook = XLSX.utils.book_new(); const worksheet = XLSX.utils.json_to_sheet(data); XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); // 设置工作表名称 const buffer = XLSX.writeFile(workbook, 'output.xlsx'); ``` 5. **下载文件**:最后,你可以提供一个链接让用户点击下载,或者使用`FileSaver.js`之类的库将文件内容直接下载给用户。 注意:由于虚拟化表格是懒加载的,所以在实际操作中可能需要特殊处理,确保在导出前已全部加载了数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值