diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 865f35a..c0525f8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,7 +3,7 @@ name: Publish Package on: push: branches: - - dev + - main jobs: publish: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bbdf46..fb7ebad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.0.1 + +### fix + +- virtual list bug | 虚拟列表漏洞 + ## 1.0.0 ### Breaking Changes (破坏性更新) diff --git a/README.md b/README.md index a12352a..3388809 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ app.use(VueVirtualWaterfall) | virtual | boolean | true | Enable virtual list | | rowKey | string | 'id' | Key for v-for | | gap | number | 15 | Gap between each item | -| preloadScreenCount | `[number, number]` | `[1, 0]` | Preload screen count `[above, below]` | +| preloadScreenCount | `[number, number]` | `[0, 0]` | Preload screen count `[above, below]` | | itemMinWidth | number | 220 | Minimum width for each item | | maxColumnCount | number | 10 | Maximum number of columns | | minColumnCount | number | 2 | Minimum number of columns | diff --git a/README.zh.md b/README.zh.md index 0513754..cebb01a 100644 --- a/README.zh.md +++ b/README.zh.md @@ -55,7 +55,7 @@ app.use(VueVirtualWaterfall) | virtual | boolean | true | 是否启用虚拟列表 | | rowKey | string | 'id' | v-for需要用到key | | gap | number | 15 | 每个item之间的间隔 | -| preloadScreenCount | `[number, number]` | `[1:0]` | 预加载屏数量`[上面预加载屏数,下面预加载屏数]` | +| preloadScreenCount | `[number, number]` | `[0:0]` | 预加载屏数量`[上面预加载屏数,下面预加载屏数]` | | itemMinWidth | number | 220 | 每个item最小宽度 | | maxColumnCount | number | 10 | 允许的最大列数 | | minColumnCount | number | 2 | 允许的最小列数 | diff --git a/package.json b/package.json index 6b67ad4..8b34c87 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@lhlyu/vue-virtual-waterfall", "description": "vue3 virtual waterfall component", - "version": "1.0.0", + "version": "1.0.1", "author": "lhlyu", "repository": { "type": "git", @@ -47,7 +47,7 @@ "typescript": "^5.3.3", "vite": "^5.0.10", "vite-plugin-dts": "^3.6.4", - "vue": "^3.3.11", + "vue": "^3.3.12", "vue-tsc": "^1.8.25" } } diff --git a/src/example/Example.vue b/src/example/Example.vue index 19bffa4..ee21f68 100644 --- a/src/example/Example.vue +++ b/src/example/Example.vue @@ -75,7 +75,9 @@
- +
列列
@@ -144,6 +146,7 @@
+

每页条数: {{ data.size }}

当前页码: {{ data.page }} / {{ data.max }}

已加载量: {{ data.list.length }} / {{ data.total }}

等待加载: {{ waterfallOption.loading }}

diff --git a/src/example/useWaterfall.ts b/src/example/useWaterfall.ts index 2d2704f..72fc4f7 100644 --- a/src/example/useWaterfall.ts +++ b/src/example/useWaterfall.ts @@ -55,7 +55,7 @@ const useWaterfall = () => { bottomDistance: 0, // 是否只展示图片,这是自定义加的一个属性 onlyImage: false, - topPreloadScreenCount: 1, + topPreloadScreenCount: 0, bottomPreloadScreenCount: 0, virtual: true, gap: 15, @@ -78,7 +78,7 @@ const useWaterfall = () => { // 需要展示数据的属性 const data = reactive({ page: 0, - size: 40, + size: 30, total: 0, max: 0, list: [] as ItemOption[], @@ -134,9 +134,10 @@ const useWaterfall = () => { measure() if (arrivedState['bottom']) { if (!promise.value) { - promise.value = Promise.all([loadData(), new Promise(resolve => setTimeout(resolve, 100))]).finally(() => { + promise.value = Promise.all([loadData(), new Promise(resolve => setTimeout(resolve, 100))]).finally(async () => { promise.value = null - nextTick(() => checkAndLoad()) + await nextTick() + checkAndLoad() }) } } diff --git a/src/vue-virtual-waterfall/virtual-waterfall.vue b/src/vue-virtual-waterfall/virtual-waterfall.vue index 8ead797..a13e564 100644 --- a/src/vue-virtual-waterfall/virtual-waterfall.vue +++ b/src/vue-virtual-waterfall/virtual-waterfall.vue @@ -60,7 +60,7 @@ const props = withDefaults(defineProps(), { virtual: true, rowKey: 'id', gap: 15, - preloadScreenCount: () => [1, 0], + preloadScreenCount: () => [0, 0], itemMinWidth: 220, maxColumnCount: 10, minColumnCount: 2, @@ -120,6 +120,7 @@ interface SpaceOption { column: number top: number left: number + bottom: number height: number } @@ -154,13 +155,14 @@ watchEffect(() => { const columnIndex = getColumnIndex() // 计算元素的高度 const h = props.calcItemHeight(props.items[i], itemWidth.value) - + const top = columnsTop.value[columnIndex] const space: SpaceOption = { index: i, item: props.items[i], column: columnIndex, - top: columnsTop.value[columnIndex], + top: top, left: (itemWidth.value + props.gap) * columnIndex + props.gap, + bottom: top + h, height: h } @@ -180,11 +182,16 @@ const itemRenderList = computed(() => { if (!props.virtual) { return itemSpaces.value } - const tp = -contentTop.value + + // 父节点距离顶部的距离 + const parentTop = content.value.parentElement.offsetTop + + const tp = -contentTop.value + parentTop const [topPreloadScreenCount, bottomPreloadScreenCount] = props.preloadScreenCount // 避免多次访问 const innerHeight = content.value.parentElement.clientHeight + // 顶部的范围: 向上预加载preloadScreenCount个屏幕,Y轴上部 const topLimit = tp - topPreloadScreenCount * innerHeight // 底部的范围: 向下预加载preloadScreenCount个屏幕 @@ -192,21 +199,12 @@ const itemRenderList = computed(() => { const list = [] - // 判断是否已经筛选到了数据 - let open = false - for (let i = 0; i < length; i++) { - // AND 运算比 OR 运算快 - if (itemSpaces.value[i].top > topLimit && itemSpaces.value[i].top < bottomLimit) { - open = true + if ((itemSpaces.value[i].top >= topLimit || itemSpaces.value[i].bottom >= topLimit) && (itemSpaces.value[i].top <= bottomLimit || itemSpaces.value[i].bottom <= bottomLimit)) { list.push(itemSpaces.value[i]) - continue - } - // 后面的不用再遍历了 - if (open) { - break } } + return list }) diff --git a/tsconfig.json b/tsconfig.json index 88757b5..01976da 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ESNext", "DOM", "DOM.Iterable"], "skipLibCheck": true, /* Bundler mode */