Libon

virtual scroll list for vue

1 分钟 #vue
实现 Vue 版适用于表格的虚拟虚拟滚动

ToC

1
import { tableViewData } from './xxx.js'
2
3
const OVER_SCAN = 2;
4
const ITEM_HEIGHT = 32;
5
6
export const containerRef = ref(null); // 外部容器引用
7
8
export const renderViewData = ref([]); // 给外部实际渲染的数据,会根据数据的显示状态获取到正确的数据
9
51 collapsed lines
10
const size = useElementSize(containerRef); // 容器高度
11
export const ranges = ref({ from: 0, to: 0 }); // 数据取值范围
12
13
export const placeholderHeight = computed(() => ({
14
head: ranges.value.from * ITEM_HEIGHT + "px",
15
}));
16
17
// 将不展示的数据过滤, 防止隐藏的数据参与计算导致页面渲染的元素不正确的问题
18
const source = computed(() =>
19
tableViewData.value.filter((row) => getConfigOfRowKey(row).display)
20
);
21
22
const getViewCapacity = (containerHeight) => {
23
return Math.ceil(containerHeight / ITEM_HEIGHT);
24
};
25
26
const getOffset = (scrollTop) => {
27
return Math.floor(scrollTop / ITEM_HEIGHT) + 1;
28
};
29
30
export const calculateRange = () => {
31
const element = containerRef.value;
32
if (!element) {
33
return;
34
}
35
36
const offset = getOffset(element.scrollTop);
37
const viewCapacity = getViewCapacity(element.clientHeight - 38 - 7); // 表头高度 + 横向滚动条高度
38
39
const start = offset - OVER_SCAN;
40
const end = offset + viewCapacity + OVER_SCAN;
41
42
ranges.value = {
43
from: start < 0 ? 0 : start,
44
to: end > source.value.length ? source.value.length : end,
45
};
46
47
nextTick(() => {
48
// 计算需要渲染到页面中的数据
49
renderViewData.value = source.value.slice(
50
ranges.value.from,
51
ranges.value.to
52
);
53
});
54
};
55
56
watch(
57
// 当容器的高度或者数据源变化则重新计算数据区间
58
[size.height, tableViewData],
59
debounce(() => calculateRange(), 200)
60
);

CD ..