vue2 element ui el-table大数据处理无分页解决方案-分片加载

实现:

   当数据量大,无分页后台一次全部返回数据,如果直接el-table渲染会造成页面渲染卡死

 

 分片加载 截取数组中指定条数返显 使用:  slice

完整vue 代码,有注解,如果使用接口分页把延迟 改为 实际接口

 

<template>
  <div class="table-demo">
    <!--  @scroll="testcroll" 未生效 考虑其他方式 -->
    <!-- 优先使用 el-table 内置 @scroll 事件(更简洁,无需手动操作DOM) -->
    <el-table
      ref="myTable"
      :data="tableData"
      height="300"
      border
      stripe
    >
      <el-table-column prop="id" label="序号" width="100" />
      <el-table-column prop="name" label="姓名" width="150" />
      <el-table-column prop="address" label="地址" min-width="200" />
    </el-table>
  </div>
</template>

<script>
// 引入 lodash 节流(若项目未集成,可使用自定义节流函数)
import _ from "lodash";

export default {
  name: "ElTableScrollCorrect",
  data() {
    return {
      scrollContainer: null,
      originData: [], // 大数据量存储
      tableData: [], // 当前页面表格渲染
      pageSize: 100, // 每次加载100条(可根据性能调整,建议50-200)
      currentPage: 1, // 当前加载到第几页
      loading: false, // 是否正在加载
      noMore: false, // 是否已加载全部数据
    };
  },
  created() {
    // 模拟5万条数据(原1000条可改为50000,测试大数据场景)
    this.generateTestData(50000);
  },
  beforeDestroy() {
    // 组件销毁前,移除事件监听(防止内存泄漏)
    if (this.scrollContainer) {
      this.scrollContainer.removeEventListener(
        "scroll",
        this.handleTableScroll
      );
    }
  },

  mounted() {
    // 组件挂载后,获取内部滚动容器
    this.scrollContainer = this.$refs.myTable.$el.querySelector(
      ".el-table__body-wrapper"
    );
    // 绑定原生 scroll 事件
    if (this.scrollContainer) {
      this.scrollContainer.addEventListener("scroll", this.handleTableScroll);
    }
  },
  methods: {
    /**
     * 生成模拟数据(优化:批量生成,减少冗余逻辑)
     * @param {Number} count - 数据总量
     */
    generateTestData(count) {
      // 批量生成数据,避免手动循环的冗余写法
      const data = Array.from({ length: count }, (_, index) => ({
        id: index + 1,
        name: `用户${index + 1}`,
        address: `北京市朝阳区${index + 1}号街道`,
      }));

      // 冻结原始数据,禁用响应式(核心优化:减少Vue监听开销)
      this.originData = Object.freeze(data);
      // 初始化加载第一页数据
      this.loadMoreData();
    },

    /**
     * 表格滚动事件处理(优化:节流处理,减少事件触发频率)
     * @param {Object} scrollInfo - 滚动信息对象(scrollTop/scrollHeight/clientHeight)
     */
    handleTableScroll: _.throttle(function (scrollInfo) {
      const { scrollTop, scrollHeight, clientHeight } = scrollInfo.target;
      console.log(scrollTop, scrollHeight, clientHeight)
      // 滚动距离底部50px时触发加载(优化:增加边界判断,避免无效触发)
      const isNearBottom = scrollTop + clientHeight >= scrollHeight - 500;
      // 仅当接近底部、未加载中、还有数据时,才触发加载
      if (isNearBottom && !this.loading && !this.noMore) {
          console.log('scrollInfo',scrollInfo)
        this.loadMoreData();
      }
    }, 500), // 500ms内仅触发一次,优化性能

    /**
     * 加载更多数据的核心方法(优化:逻辑严谨性,减少冗余操作)
     */
    async loadMoreData() {
      // 避免重复加载(前置判断,快速返回)
      if (this.loading || this.noMore) return;

      this.loading = true;
      try {
        // 模拟接口请求延迟(实际项目替换为真实接口调用,建议用async/await)
        await this.mockApiRequest();

        // 计算数据索引(优化:边界处理,避免超出数组长度)
        const start = (this.currentPage - 1) * this.pageSize;
        const end = Math.min(start + this.pageSize, this.originData.length);
        // 切片获取当前页数据并冻结(减少响应式开销)
        const newData = Object.freeze(this.originData.slice(start, end));

        // 批量追加数据(优化:避免循环push,减少视图更新次数)
        this.tableData = [...this.tableData, ...newData];

        // 更新分页状态
        this.currentPage += 1;
        // 判断是否加载完毕(优化:精准判断,避免无效加载)
        this.noMore = end >= this.originData.length;
      } catch (error) {
        console.error("数据加载失败:", error);
        this.$message?.error("数据加载失败,请稍后重试"); // 新增:错误提示
      } finally {
        // 无论成功失败,都解除加载锁(优化:避免加载状态卡死)
        this.loading = false;
      }
    },

    /**
     * 模拟接口请求(优化:抽离为独立方法,便于替换真实接口)
     * @returns {Promise} - 模拟请求Promise
     */
    mockApiRequest() {
      return new Promise((resolve) => {
        setTimeout(resolve, 300); // 缩短延迟时间,提升用户体验 
      });
    },
  }, 
};
</script>

<style scoped>
 
 
</style>

 

posted on 2025-12-22 14:19  Mc525  阅读(15)  评论(0)    收藏  举报

导航