大数据渲染

160 阅读1分钟

方案1 表格滚动触底加载(滚动到底,再加载)

这里重点就是我们需要去判断,何时滚动条触底。

笔者举例是使用的插件v-el-table-infinite-scroll,本质上这个插件是一个自定义指令。对应npm地址:www.npmjs.com/package/el-…

当然也有别的插件,如vue-scroller 等:一个意思,不赘述

注意,触底加载也是要分堆的,将发请求获取到的十万条数据,进行分好堆,然后每触底一次,就加载一堆即可

在el-table中使用el-table-infinite-scroll指令步骤

安装,注意版本号(区分vue2和vue3)

cnpm install --save el-table-infinite-scroll@1.0.10

// 使用无限滚动插件

import elTableInfiniteScroll from 'el-table-infinite-scroll';

Vue.use(elTableInfiniteScroll);

因为是一个自定义指令,所以直接写在el-table标签上即可

<el-table
  v-el-table-infinite-scroll="load"
  :data="tableData"
>
  <el-table-column prop="id" label="ID"></el-table-column>
  <el-table-column prop="name" label="名字"></el-table-column>
</el-table>

async load() {
    // 触底加载,展示数据...
},

案例代码

<template>
  <div class="box">
    <el-table
      v-el-table-infinite-scroll="load"
      height="600"
      :data="tableData"
      border
      style="width: 80%"
      v-loading="loading"
      element-loading-text="数据量太大啦,客官稍后..."
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(255, 255, 255, 0.5)"
      :header-cell-style="{
        height: '24px',
        lineHeight: '24px',
        color: '#606266',
        background: '#F5F5F5',
        fontWeight: 'bold',
      }"
    >
      <el-table-column type="index" label="序"></el-table-column>
      <el-table-column prop="id" label="ID"></el-table-column>
      <el-table-column prop="name" label="名字"></el-table-column>
      <el-table-column prop="value" label="对应值"></el-table-column>
    </el-table>
  </div>
</template>

<script>
// 分堆函数
function averageFn(arr) {
  let i = 0;
  let result = [];
  while (i < arr.length) {
    result.push(arr.slice(i, i + 10)); // 一次截取10个用于分堆
    i = i + 10; // 这10个截取完,再准备截取下10个
  }
  return result;
}
import axios from "axios";
export default {
  data() {
    return {
      allTableData: [], // 初始发请求获取所有的数据
      tableData: [], // 要展示的数据
      loading: false
    };
  },
  // 第一步,发请求,获取大量数据,并转成二维数组,分堆分组分块存储
  async created() {
    this.loading = true;
    const res = await axios.get("http://ashuai.work:10000/bigData");
    this.allTableData = averageFn(res.data.data); // 使用分堆函数,存放二维数组
    // this.originalAllTableData = this.allTableData // 也可以存一份原始值,留作备用,都行的
    this.loading = false;
    // 第二步,操作完毕以后,执行触底加载方法
    this.load(); 
  },
  methods: {
    // 初始会执行一次,当然也可以配置,使其不执行
    async load() {
      console.log("自动多次执行之,首次执行会根据高度去计算要执行几次合适");
      // 第五步,触底加载相当于把二维数组的每一项取出来用,取完用完时return停止即可
      if (this.allTableData.length == 0) {
        console.log("没数据啦");
        return;
      }
      // 第三步,加载的时候,把二维数组的第一项取出来,拼接到要展示的表格数据中去
      let arr = this.allTableData[0];
      this.tableData = this.tableData.concat(arr);
      // 第四步,拼接展示以后,再把二维数组的第一项的数据删除即可
      this.allTableData.shift();
    },
  },
};
</script>

方案2 使用无限加载/虚拟列表进行展示

案例代码




<template>
  <!-- 虚拟列表容器,类似“窗口”,窗口的高度取决于一次展示几条数据
            比如窗口只能看到10条数据,一条40像素,10400像素
            故,窗口的高度为400像素,注意要开定位和滚动条 -->
  <div
    class="virtualListWrap"
    ref="virtualListWrap"
    @scroll="handleScroll"
    :style="{ height: itemHeight * count + 'px' }"
  >
    <!-- 占位dom元素,其高度为所有的数据的总高度 -->
    <div
      class="placeholderDom"
      :style="{ height: allListData.length * itemHeight + 'px' }"
    ></div>
    <!-- 内容区,展示10条数据,注意其定位的top值是变化的 -->
    <div class="contentList" :style="{ top: topVal }">
      <!-- 每一条(项)数据 -->
      <div
        v-for="(item, index) in showListData"
        :key="index"
        class="itemClass"
        :style="{ height: itemHeight + 'px' }"
      >
        {{ item.name }}
      </div>
    </div>
    <!-- 加载中部分 -->
    <div class="loadingBox" v-show="loading">
      <i class="el-icon-loading"></i>
      &nbsp;&nbsp;<span>loading...</span>
    </div>
  </div>
</template>
<script>
import axios from "axios";
export default {
  data() {
    return {
      allListData: [], // 所有的数据,比如这个数组存放了十万条数据
      itemHeight: 40, // 每一条(项)的高度,比如40像素
      count: 10, // 一屏展示几条数据
      start: 0, // 开始位置的索引
      end: 10, // 结束位置的索引
      topVal: 0, // 父元素滚动条滚动,更改子元素对应top定位的值,确保联动
      loading: false,
    };
  },
  computed: {
    // 从所有的数据allListData中截取需要展示的数据showListData
    showListData: function () {
      return this.allListData.slice(this.start, this.end);
    },
  },
  async created() {
    this.loading = true;
    const res = await axios.get("http://ashuai.work:10000/bigData");
    this.allListData = res.data.data;
    this.loading = false;
  },
  methods: {
    // 滚动这里可以加上节流,减少触发频次
    handleScroll() {
      /**
       * 获取在垂直方向上,滚动条滚动了多少像素距离Element.scrollTop
       *
       * 滚动的距离除以每一项的高度,即为滚动到了多少项,当然,要取个整数
       * 例:滚动4米,一步长0.8米,滚动到第几步,4/0.8 = 第5步(取整好计算)
       *
       * 又因为我们一次要展示10项,所以知道了起始位置项,再加上结束位置项,
       * 就能得出区间了【起始位置, 起始位置 + size项数】==【起始位置, 结束位置】
       * */
      const scrollTop = this.$refs.virtualListWrap.scrollTop;
      this.start = Math.floor(scrollTop / this.itemHeight);
      this.end = this.start + this.count;
      /**
       * 动态更改定位的top值,确保联动,动态展示相应内容
       * */
      this.topVal = this.$refs.virtualListWrap.scrollTop + "px";
    },
  },
};
</script>
<style scoped lang="less">
// 虚拟列表容器盒子
.virtualListWrap {
  box-sizing: border-box;
  width: 240px;
  border: solid 1px #000000;
  // 开启滚动条
  overflow-y: auto;
  // 开启相对定位
  position: relative;
  .contentList {
    width: 100%;
    height: auto;
    // 搭配使用绝对定位
    position: absolute;
    top: 0;
    left: 0;
    .itemClass {
      box-sizing: border-box;
      width: 100%;
      height: 40px;
      line-height: 40px;
      text-align: center;
    }
    // 奇偶行改一个颜色
    .itemClass:nth-child(even) {
      background: #c7edcc;
    }
    .itemClass:nth-child(odd) {
      background: pink;
    }
  }
  .loadingBox {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(255, 255, 255, 0.64);
    color: green;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>

方案3:前端分页

方案4:定时器分步渲染,每次渲染100条。例如共10000条数据,分100次渲染完