10万条数据优化方案

1. 虚拟列表渲染(Virtual Scrolling)

虚拟列表渲染通过只渲染可见区域的数据,减少 DOM 元素的数量,从而提高性能。这在处理大数据列表时非常有效。

示例代码:

<template>
  <div class="list-container" ref="listContainer" @scroll="onScroll">
    <div class="list" :style="{ height: totalHeight + 'px' }">
      <div
        v-for="item in visibleItems"
        :key="item.id"
        class="list-item"
        :style="{ transform: `translateY(${item.offset}px)` }"
      >
        {{ item.text }}
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { ref, computed, onMounted } from 'vue';

export default {
  setup() {
    const itemHeight = 50; // 每个列表项的高度
    const visibleCount = 20; // 可见区域内显示的项数
    const listContainer = ref(null);
    const items = Array.from({ length: 100000 }, (_, index) => ({
      id: index + 1,
      text: `Item ${index + 1}`,
      offset: index * itemHeight,
    }));

    const scrollTop = ref(0);

    const visibleItems = computed(() => {
      const start = Math.floor(scrollTop.value / itemHeight);
      const end = start + visibleCount;
      return items.slice(start, end);
    });

    const totalHeight = computed(() => items.length * itemHeight);

    const onScroll = () => {
      scrollTop.value = listContainer.value?.scrollTop || 0;
    };

    onMounted(() => {
      listContainer.value.scrollTop = 0;
    });

    return {
      listContainer,
      visibleItems,
      totalHeight,
      onScroll,
    };
  },
};
</script>

<style scoped>
.list-container {
  height: 100vh;
  overflow-y: auto;
  position: relative;
}
.list {
  position: relative;
}
.list-item {
  height: 50px;
  position: absolute;
  width: 100%;
  box-sizing: border-box;
  padding: 0 16px;
  border-bottom: 1px solid #ddd;
}
</style>

2. 分页加载(Pagination)

在数据量非常大的情况下,通常会使用分页加载的方式,分批获取数据,减轻页面加载压力。

示例代码:

<template>
  <div>
    <ul>
      <li v-for="item in currentPageData" :key="item.id">
        {{ item.text }}
      </li>
    </ul>
    <button @click="loadMore">加载更多</button>
  </div>
</template>

<script lang="ts">
import { ref } from 'vue';

export default {
  setup() {
    const items = Array.from({ length: 100000 }, (_, index) => ({
      id: index + 1,
      text: `Item ${index + 1}`,
    }));
    
    const pageSize = 1000;
    const currentPage = ref(1);

    const currentPageData = ref(items.slice(0, pageSize));

    const loadMore = () => {
      currentPage.value++;
      currentPageData.value = currentPageData.value.concat(
        items.slice((currentPage.value - 1) * pageSize, currentPage.value * pageSize)
      );
    };

    return {
      currentPageData,
      loadMore,
    };
  },
};
</script>

3. 使用 Web Worker 进行数据处理

对于需要进行复杂计算或处理的大数据,可以考虑使用 Web Worker 来在后台线程中处理数据,避免阻塞主线程的渲染。

示例代码:

  1. 创建 Web Worker 文件 (worker.js):

self.onmessage = function (event) {
  const data = event.data;
  // 进行复杂数据处理
  const processedData = data.map(item => item * 2);
  postMessage(processedData);
};

        2.在 Vue 组件中使用 Web Worker:

<template>
  <div>
    <ul>
      <li v-for="item in processedData" :key="item.id">{{ item }}</li>
    </ul>
  </div>
</template>

<script lang="ts">
import { ref, onMounted } from 'vue';

export default {
  setup() {
    const processedData = ref([]);

    onMounted(() => {
      const worker = new Worker(new URL('./worker.js', import.meta.url));
      const items = Array.from({ length: 100000 }, (_, index) => index + 1);

      worker.postMessage(items);

      worker.onmessage = function (event) {
        processedData.value = event.data;
      };
    });

    return {
      processedData,
    };
  },
};
</script>

4. 使用 vue-virtual-scroller

你还可以直接使用现成的库如 vue-virtual-scroller,它已经为你封装好了虚拟滚动的逻辑。

<template>
  <div>
    <RecycleScroller
      :items="items"
      :item-size="50"
      key-field="id"
    >
      <template #default="{ item }">
        <div class="item">{{ item.text }}</div>
      </template>
    </RecycleScroller>
  </div>
</template>

<script lang="ts">
import { RecycleScroller } from 'vue-virtual-scroller';
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';

export default {
  components: {
    RecycleScroller,
  },
  setup() {
    const items = Array.from({ length: 100000 }, (_, index) => ({
      id: index + 1,
      text: `Item ${index + 1}`,
    }));

    return {
      items,
    };
  },
};
</script>

<style scoped>
.item {
  height: 50px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #ddd;
  padding: 0 16px;
}
</style>

5.数据分片与延迟加载(Chunking and Lazy Loading)

对于初始加载大量数据,可以将数据分片,分批加载或通过延迟加载来减轻前端负担。

示例代码:

<template>
  <div>
    <ul>
      <li v-for="item in visibleItems" :key="item.id">
        {{ item.text }}
      </li>
    </ul>
    <button @click="loadMore">加载更多</button>
  </div>
</template>

<script lang="ts">
import { ref } from 'vue';
import axios from 'axios';

export default {
  setup() {
    const chunkSize = 5000;
    const items = ref([]);
    const visibleItems = ref([]);
    let currentChunkIndex = 0;

    const fetchChunkData = async () => {
      const response = await axios.get('/api/data', {
        params: {
          start: currentChunkIndex * chunkSize,
          size: chunkSize,
        },
      });
      items.value = items.value.concat(response.data);
      visibleItems.value = items.value.slice(0, (currentChunkIndex + 1) * chunkSize);
      currentChunkIndex++;
    };

    const loadMore = () => {
      fetchChunkData();
    };

    fetchChunkData();

    return {
      visibleItems,
      loadMore,
    };
  },
};
</script>

6. 前端搜索优化(Optimized Search on Frontend)

对前端进行搜索优化时,避免每次都遍历整个数据集。可以使用以下方法:

1. 使用哈希表(Hash Table)加速查找

将数据存储在哈希表(对象或 Map)中,可以在 O(1) 时间内查找。

2. 索引构建(Indexing)

在获取数据后,构建索引以加速特定字段的查找。可以预先在某些字段上创建索引,如 ID 或名称。

import { ref, computed, onMounted } from 'vue';
import axios from 'axios';

export default {
  setup() {
    const items = ref([]);
    const itemsMap = ref(new Map());

    onMounted(async () => {
      const response = await axios.get('/api/data');
      items.value = response.data;

      // 构建索引
      items.value.forEach(item => {
        itemsMap.value.set(item.id, item);
      });
    });

    // 根据 ID 快速查找
    const findItemById = (id) => {
      return itemsMap.value.get(id);
    };

    return {
      findItemById,
    };
  },
};

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值