elementUi表格数据量大操作卡顿问题

业务场景

在项目开发中,使用表格展示数据是最常见的需求,对于成千上万的数据来说渲染会造成浏览器渲染加载慢或者是卡顿甚至浏览器崩溃。

解决方法

对于element-ui表格一次性加载10000条数据会导致浏览器卡顿或者崩溃, 这里使用vxe Table 解决渲染卡顿问题,官网网址:https://vxetable.cn/v3/#/start/install

安装 vxe Table

  1. 完整安装表格和配套 UI 库
npm install vxe-pc-ui@3.3.1 vxe-table@3.11.2
# 或者
yarn add vxe-pc-ui@3.3.1 vxe-table@3.11.2
# 或者
pnpm add vxe-pc-ui@3.3.1 vxe-table@3.11.2

 // ...
 import VxeUI from 'vxe-pc-ui'
 import 'vxe-pc-ui/lib/style.css'
 import VxeUITable from 'vxe-table'
 import 'vxe-table/lib/style.css'
 // ...

 Vue.use(VxeUI)
 Vue.use(VxeUITable)
 // ...
  1. 安装纯表格
npm install vxe-table@3.11.2
# 或者
yarn add vxe-table@3.11.2
# 或者
pnpm add vxe-table@3.11.2

// ...
import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css'
// ...

Vue.use(VxeUITable)
// ...

封装成Table组件

为了复用封装成一个独立的table带分页的组件

  1. 大数据表格组件 组件取名bigDataTable
<template>
  <div class="tab-container">
    <div class="table-box" style="padding: 0;">
      <vxe-table
        :data="data"
        :scroll-x="{ enabled: true, gt: 0 }"
        :scroll-y="{ enabled: true, gt: 0, mode: 'wheel' }"
        :column-config="{ resizable: true }"
        class="vxe-table"
        height="100%"
        show-overflow
        stripe
        show-header-overflow
        show-footer-overflow
        border
        align="center"
        @checkbox-all="handleSelectionChange"
        @checkbox-change="handleSelectionChange">
        <vxe-column v-if="isSelection" type="checkbox" width="60"/>
        <vxe-column v-if="isTableIndex" type="seq" width="60"/>
        <template v-for="item in columns">
          <vxe-column v-if="item.isShow" :key="item.fieldCode" :field="item.fieldCode" :title="item.fieldName">
            <template #default="{ row }">
              <span v-if="item.onclick" class="underLine" @click="item.onclick(row)">{{ fieldValueByRowRenderer(row, item) }}</span>
              <span v-else>{{ row[item.fieldCode] ? fieldValueByRowRenderer(row, item) : '-' }}</span>
            </template>
          </vxe-column>
        </template>
        <vxe-column v-if="filterRowButtons().length > 0" :width="rowButtonsWidth" label="操作" fixed="right" align="center">
          <template #default="{ row }">
            <div v-if="filterRowButtons(row).length <= 3">
              <template v-for="(item, index) in filterRowButtons(row)">
                <el-button v-has="item.permission" v-if="isShowButton(item, row)" :key="index" type="text" @click="item.click(row)">{{ item.label }}</el-button>
              </template>
            </div>
            <div v-else>
              <el-button v-has="filterRowButtons(row)[0].permission" v-if="isShowButton(filterRowButtons(row)[0], row)" type="text" @click="filterRowButtons(row)[0].click(row)">{{ filterRowButtons(row)[0].label }}</el-button>
              <el-button v-has="filterRowButtons(row)[1].permission" v-if="isShowButton(filterRowButtons(row)[1], row)" type="text" @click="filterRowButtons(row)[1].click(row)">{{ filterRowButtons(row)[1].label }}</el-button>
              <el-dropdown trigger="click">
                <span class="el-dropdown-link">更多<i class="el-icon-caret-bottom el-icon--right" /> </span>
                <el-dropdown-menu slot="dropdown" class="dropDown">
                  <el-dropdown-item class="clearfix">
                    <template v-for="(item, index) in filterRowButtons(row).filter((el, index) => index > 1)">
                      <el-button v-has="item.permission" v-if="isShowButton(item, row)" :key="index" type="text" @click="item.click(row)">{{ item.label }}</el-button>
                    </template>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
            </div>
          </template>
        </vxe-column>
      </vxe-table>
    </div>
    <div class="pagination">
      <el-pagination
        :current-page="currPage"
        :page-size="pageSize"
        :page-sizes="pageSizes"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        @current-change="handlePageChange"
        @size-change="handleSizeChange"
      />
    </div>
  </div>

</template>
<script>
import store from '@/store'
export default {
  name: 'Table',
  props: {
    // 是否加载中
    isLoading: {
      type: Boolean,
      default: false
    },
    // 表格序号
    isTableIndex: {
      type: Boolean,
      default: false
    },
    // 表格复选框
    isSelection: {
      type: Boolean,
      default: false
    },
    // 当前页
    currPage: {
      type: Number,
      default: 1
    },
    // 每页条数
    pageSize: {
      type: Number,
      default: 10
    },
    // 总条数
    total: {
      type: Number,
      default: 0
    },
    // 分页条数
    pageSizes: {
      type: Array,
      default: () => [10, 50, 100, 300, 500, 1000, 8000]
    },
    // 表格数据
    data: {
      type: Array,
      default: () => []
    },
    // 表头数据
    columns: {
      type: Array,
      default: () => []
    },
    rowButtonsWidth: {
      type: Number,
      default: 120
    },
    // 行按钮
    rowButtons: {
      type: Array,
      default: () => []
    }
  },
  computed: {
    // 过滤没有权限的 和按钮不显示的数据
    filterRowButtons() {
      // 系统所有的按钮权限
      const userPermissions = store.getters && store.getters.userPermissions
      return (row) => {
        if (!row) return this.rowButtons
        this.rowButtons.forEach(item => {
          if (item.isShow && typeof item.isShow === 'function') {
            item.isFlag = item.isShow(row)
          } else {
            item.isFlag = item.isShow
          }
        })
        return this.rowButtons.filter(item => {
          if (item.permission) {
            return userPermissions.includes(item.permission) && item.isFlag
          } else {
            return item.isFlag
          }
        })
      }
    }
  },
  methods: {
    // 带表格列格式化的值
    fieldValueByRowRenderer(row, columnConfig) {
      if (!columnConfig || typeof columnConfig.fieldTableRowRenderer != 'function') {
        return row[columnConfig.fieldCode]
      }
      return columnConfig.fieldTableRowRenderer(row)
    },
    // 是否展示按钮
    isShowButton(item, row) {
      if (typeof item.isShow === 'function') {
        return item.isShow(row)
      } else {
        return item.isShow
      }
    },
    // 选中的值
    handleSelectionChange(val) {
      this.$emit('selectionChange', val)
    },
    handlePageChange(val) {
      this.$emit('pageChange', val)
    },
    handleSizeChange(val) {
      this.$emit('sizeChange', val)
    },
    doLayout() {
      this.$nextTick(() => {
        this.$refs.table.doLayout()
      })
    }
  }
}
</script>
<style scoped lang="scss">
.tab-container {
  display: flex;
    flex-direction: column;
    flex: 1;
}
.table-box {
  display: flex;
  flex-direction: column;
  flex: 1;
  .vxe-table {
    flex: 1;
  }
  .pagination {
    height: 44px;
  }
}
.underLine {
  color: #5887fb;
  cursor: pointer;
}
.underLine:hover {
  text-decoration: underline;
  color: #799ffc;
}
.el-dropdown-link{
  margin-left:5px;
  color: #5887fb;
  font-size: 12px;
}
.el-dropdown-menu__item:focus, .el-dropdown-menu__item:not(.is-disabled):hover {
    background-color: transparent;
    color: transparent;
}
::v-deep.table-box .vxe-table--header-wrapper {
  background-color: rgb(22, 93, 255, 0.15) !important;
}
</style>

  1. 使用表格组件
<template>
	<bigDataTable
	  :data="tableData"
	  :columns="columns"
	  :row-buttons="rowButtons"
	  :is-selection="true"
	  :is-table-index="true"
	  :curr-page="query.currPage"
	  :page-size="query.limit"
	  :total="pageTotal"
	  :is-loading="loading"
	  @selectionChange="handleSelectionChange"
	  @pageChange="handlePageChange"
	  @sizeChange="handleSizeChange" />
</template>
<script>
export default { 
  data() {
    return {
      columns: [
        {
          fieldName: '客户名称', // 表格头
          fieldCode: 'companyName', // 字段名
          minWidth: 120,
          isShow: true,
          selectShow: 1
          // fieldTableRowRenderer: (row) => { // 处理当前行数据
          //   return 2
          // },
          // onclick: (row) => { // 当前字段点击事件
          //   console.log(row)
          // }
        }
        ...
      ],
      rowButtons: [
         {
          label: '审核',
          permission: '', // 权限码
          isShow: (row) => { // 按钮是否显示 数据类型 boolean 和 function
            return true
          },
          click: this.click  // 行按钮操作事件
        },
      ]
    }
  }
}
</script>

说明:

  1. data -> 表格数据源
  2. columns -> 表格每列配置项
  3. row-buttons -> 表格行按钮操作
  4. is-selection -> 复选框是否显示
  5. is-table-index -> 表格序列号是否显示
  6. curr-page -> 表格分页当前页数
  7. page-size -> 表格分页每页页数
  8. total -> 表格总页页数
  9. selectionChange-> 复选框选中事件
  10. pageChange-> 分页事件
  11. sizeChange -> 分页事件

效果图

elementUi表格数据量大操作卡顿问题_第1张图片

你可能感兴趣的:(vue.js)