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 来在后台线程中处理数据,避免阻塞主线程的渲染。
示例代码:
-
创建 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,
};
},
};