前端万级数据量表格预览及前端导出Excel方案组件封装(基于vxetable虚拟滚动和web worker)

Posted Sure小硕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端万级数据量表格预览及前端导出Excel方案组件封装(基于vxetable虚拟滚动和web worker)相关的知识,希望对你有一定的参考价值。

如题,本文主要解决前端展示渲染大数据量table数据及导出Excel的问题,主要是通过使用v3版本的vxetable和webworker来实现的。亲测可以表格可渲染30w条数据,可在10s内导出30w条数据Excel。

框架:vue2;

一、安装vxetable

可参考官网:https://vxetable.cn/v3/#/table/start/use

  1. 安装按需加载的插件
npm install babel-plugin-import -D
  1. 修改文件 .babelrc 或 babel.config.js

        "plugins": [
          [
            "import",
            
              "libraryName": "vxe-table",
              "style": true // 样式是否也按需加载
            
          ]
        ]
      


3. main.js中全局按需引入模块

import  VXETable, Icon, Column, Table  from 'vxe-table'
Vue.use(Icon).use(Column).use(Table).use(VXETable)

这样VXETable就已经在项目中安装注册完成,接下来进行安装vue-worker

二、安装vue-worker

  1. 首先安装vue-worker插件;
npm install vue-worker -S
  1. 在main.js中引入
import VueWorker from 'vue-worker'
Vue.use(VueWorker)
  1. 引入导出XLSX的包
    这里有两种方式
    第一种方式:在web worker中使用XLSX的外部CDN链接
importScripts('https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.15.3/xlsx.core.min.js')

然后就可以在web worker中全局使用XLSX了

第二张方式:将上面👆包的js链接下载到本地,放到项目的public文件夹下,可以再建一个workers文件夹存放,如下

然后再web worker中使用

//importScripts('https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.15.3/xlsx.core.min.js')
importScripts(location.origin + '/workers/xlsx.core.min.js')
//因为woker中是有loaction变量的,所以可以通过服务器的绝对路径进行访问,以获得XLSX。
const ws = XLSX.utils.aoa_to_sheet(data)

三、封装相应的table组件

下面是我封装的组件,如果是使用elementUI可以直接引入,若没有使用可以把elementUi相关标签删除替换即可。
vxe-table的Api文档:https://vxetable.cn/v3/#/table/api

组件传参说明:仅有两个参数

rowList行记录数据
colList列记录数据
<result-table :rowList="rowList" :colList="colList"> </result-table>
<template>
  <div style="height: 100%">
    <div style="display: flex; justify-content: flex-end">
      <el-pagination
        background
        layout="sizes,prev, pager, next,total"
        :page-sizes="[10, 50, 100, 500, 1000]"
        :current-page="currentPageNum"
        :page-size="currentPageSize"
        :total="rowListTotal"
        @current-change="currentChange"
        @size-change="handleSizeChange"
      >
      </el-pagination>
      <el-button
        type="primary"
        @click="handleLargeDataExport"
        size="small"
        icon="el-icon-download"
        style="z-index: 99; margin-right: 10px"
        >导出全部</el-button
      >
    </div>
    <div style="height: calc(100% - 80px); padding: 5px 10px">
      <vxe-table
        border
        ref="xTable1"
        height="100%"
        empty-text="暂无数据"
        show-overflow="title"
        style="overflow: visible"
        show-header-overflow
        :row-config=" isHover: true "
        :tooltip-config=" showAll: true "
      >
        <vxe-column
          v-for="item in colList"
          :field="item.name"
          :resizable="true"
          min-width="120"
          :title="item.name"
          :key="item.name"
        ></vxe-column>
      </vxe-table>
    </div>
  </div>
</template>
<script>
export default 
  data() 
    return 
      currentList: [], //当前页数据
      currentPageNum: 1, //当前页码
      currentPageSize: 50, //当前页尺寸
      rowListTotal: 0 //结果总条数
    
  ,
  props: 
    //行数据
    rowList: 
      type: Array,
      default: []
    ,
    // 列数据
    colList: 
      type: Array,
      default: []
    
  ,
  created() ,
  watch: 
    rowList: 
      handler(newVal, oldVal) 
        console.log('rowListHandle')
        this.rowListTotal = newVal.length
        this.currentList = newVal.slice(0, this.currentPageSize)
        this.currentPageNum = 1
      ,
      immediate: true
    ,
    currentList: 
      handler(newVal, oldVal) 
        console.log('currentListHandle')
        this.$refs.xTable1.loadData(newVal)
      
    
  ,
  methods: 
    //当前页尺寸改变
    handleSizeChange(pageSize) 
      this.currentPageSize = pageSize
      this.currentList = this.rowList.slice(
        (this.currentPageNum - 1) * this.currentPageSize,
        this.currentPageNum * this.currentPageSize
      )
    ,
    // 当前页码改变
    currentChange(pageNum) 
      this.currentPageNum = pageNum
      this.currentList = this.rowList.slice(
        (this.currentPageNum - 1) * this.currentPageSize,
        this.currentPageNum * this.currentPageSize
      )
    ,
    // 全部结果导出
    handleLargeDataExport() 
      let handleData = this.rowList
      if (handleData.length == 0) 
        return this.$message('暂无数据!')
      
      this.$message('正在导出,请稍后...')
      this.$worker
        .run(
          (handleData) => 
            // console.time('handelExcel')
            let data = handleData.map((item, index) => 
              let tempArr = []
              for (let itemKey in item) 
                tempArr.push(item[itemKey])
              
              return tempArr
            )
            let keyArr = []
            for (let itemKey in handleData[0]) 
              keyArr.push(itemKey)
            
            data.unshift(keyArr)

            importScripts(location.origin + '/workers/xlsx.core.min.js')
            // importScripts('https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.15.3/xlsx.core.min.js')
            const ws = XLSX.utils.aoa_to_sheet(data)
            const wb = XLSX.utils.book_new()
            XLSX.utils.book_append_sheet(wb, ws, 'data')
            const buf = XLSX.write(wb,  type: 'array', bookType: 'xlsx' )
            // console.timeEnd('handelExcel')
            return buf
          ,
          [handleData]
        )
        .then((res) => 
          this.$message(
            message: '已生成文件!',
            type: 'success',
            duration: 2000
          )
          const url = window.URL.createObjectURL(new Blob([res]))
          const link = document.createElement('a')
          link.href = url
          link.download = `全部结果_$new Date().getTime().xlsx`
          link.click()
        )
        .catch((err) => 
          console.log(err)
        )
    
  

</script>

以上是关于前端万级数据量表格预览及前端导出Excel方案组件封装(基于vxetable虚拟滚动和web worker)的主要内容,如果未能解决你的问题,请参考以下文章

这一定是前端Excel导出的天花板~

基于Vue + axios + WebApi + NPOI导出Excel文件

百万级数据记录量优化查询以及导出EXCEL文件编程

前端 导出为Excel 数据源为table表格 并且table中含有图片

用多线程优化Excel表格数据导入校验的接口

Vue 纯前端导出Excel