From a20c211162278e41e5a1b8f37c0bedc186bde986 Mon Sep 17 00:00:00 2001 From: erio Date: Wed, 18 Mar 2026 22:59:02 +0800 Subject: [PATCH] perf(frontend): add virtual scrolling to DataTable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace direct row rendering with @tanstack/vue-virtual. The table now only renders visible rows (~20) via padding placeholders, eliminating the rendering bottleneck when displaying 100+ rows with heavy cell components. Key changes: - DataTable.vue: integrate useVirtualizer (always-on), virtual row template with measureElement for variable row heights, defineExpose virtualizer/sortedData for external access, overflow-y/flex CSS - useSwipeSelect.ts: dual-mode support via optional SwipeSelectVirtualContext — data-driven row index lookup and selection range when virtualizer is present, original DOM-based path preserved for callers that don't pass virtualContext --- frontend/package.json | 1 + frontend/pnpm-lock.yaml | 18 ++ frontend/src/components/common/DataTable.vue | 102 ++++++++-- frontend/src/composables/useSwipeSelect.ts | 191 ++++++++++++++++--- 4 files changed, 268 insertions(+), 44 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 1b380b17..d2a6dede 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@lobehub/icons": "^4.0.2", + "@tanstack/vue-virtual": "^3.13.23", "@vueuse/core": "^10.7.0", "axios": "^1.13.5", "chart.js": "^4.4.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 37c384b4..505b72f3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@lobehub/icons': specifier: ^4.0.2 version: 4.0.2(@lobehub/ui@4.9.2)(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@tanstack/vue-virtual': + specifier: ^3.13.23 + version: 3.13.23(vue@3.5.26(typescript@5.6.3)) '@vueuse/core': specifier: ^10.7.0 version: 10.11.1(vue@3.5.26(typescript@5.6.3)) @@ -1376,6 +1379,14 @@ packages: peerDependencies: react: '>= 16.3.0' + '@tanstack/virtual-core@3.13.23': + resolution: {integrity: sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg==} + + '@tanstack/vue-virtual@3.13.23': + resolution: {integrity: sha512-b5jPluAR6U3eOq6GWAYSpj3ugnAIZgGR0e6aGAgyRse0Yu6MVQQ0ZWm9SArSXWtageogn6bkVD8D//c4IjW3xQ==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -5808,6 +5819,13 @@ snapshots: dependencies: react: 19.2.3 + '@tanstack/virtual-core@3.13.23': {} + + '@tanstack/vue-virtual@3.13.23(vue@3.5.26(typescript@5.6.3))': + dependencies: + '@tanstack/virtual-core': 3.13.23 + vue: 3.5.26(typescript@5.6.3) + '@types/d3-array@3.2.2': {} '@types/d3-axis@3.0.6': diff --git a/frontend/src/components/common/DataTable.vue b/frontend/src/components/common/DataTable.vue index 16aea107..0f05359d 100644 --- a/frontend/src/components/common/DataTable.vue +++ b/frontend/src/components/common/DataTable.vue @@ -147,28 +147,46 @@ - - - + @@ -176,6 +194,7 @@