forked from mengyxu/noob-components
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.1 KiB
96 lines
3.1 KiB
|
3 months ago
|
# Virtual Scrolling Debug Notes
|
||
|
|
|
||
|
|
## Date: 2026-04-03
|
||
|
|
|
||
|
|
## Issue: Virtual Scrolling Not Updating on Scroll
|
||
|
|
|
||
|
|
### Symptoms
|
||
|
|
- Rows weren't shifting when scrolling programmatically
|
||
|
|
- Debug info showed correct scrollTop but rows stayed the same
|
||
|
|
- Force re-render (classList toggle) fixed it momentarily
|
||
|
|
|
||
|
|
### Root Causes Found
|
||
|
|
|
||
|
|
#### 1. Vue Template Ref Auto-Unwrapping
|
||
|
|
**Problem**: `virtualizer.visibleRows` is a `ComputedRef` inside an object. Vue 3 auto-unwraps top-level refs in templates, but NOT refs nested inside objects.
|
||
|
|
|
||
|
|
**Evidence**:
|
||
|
|
```
|
||
|
|
TypeScript error: Property 'index' does not exist on type 'true | ComputedRefImpl<any> | VirtualRow[]'
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fix**: Destructure the needed values from `virtualizer`:
|
||
|
|
```typescript
|
||
|
|
const { visibleRows, totalHeight: virtualTotalHeight, onScroll } = virtualizer;
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. Vue 3 Template `.value` Usage
|
||
|
|
**Problem**: In Vue 3 `<script setup>`, refs are auto-unwrapped in templates. Using `.value` explicitly on refs returned from a hook (inside an object) causes type inference issues.
|
||
|
|
|
||
|
|
**Before (broken)**:
|
||
|
|
```vue
|
||
|
|
<div v-for="row in virtualizer.visibleRows.value">
|
||
|
|
```
|
||
|
|
|
||
|
|
**After (working)**:
|
||
|
|
```vue
|
||
|
|
<div v-for="row in visibleRows">
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. Overscan + Small Dataset
|
||
|
|
**Problem**: With 10 rows (each ~60px = 600px total) and viewport 306px, overscan=5 means all 10 rows are rendered regardless of scroll position.
|
||
|
|
|
||
|
|
**Calculation**:
|
||
|
|
- Viewport shows ~5 rows
|
||
|
|
- Overscan 5 = render rows -5 to +5 from viewport edge
|
||
|
|
- 5 + 5 + visible rows = all 10 rows always visible
|
||
|
|
|
||
|
|
**Not a bug** - virtual scrolling only benefits when rows > viewport + overscan.
|
||
|
|
|
||
|
|
### Key Code Changes
|
||
|
|
|
||
|
|
#### list-table-v2.vue
|
||
|
|
```typescript
|
||
|
|
// Before: all refs nested in object
|
||
|
|
const virtualizer = useVirtualRows(...);
|
||
|
|
|
||
|
|
// After: destructure for template auto-unwrap
|
||
|
|
const { visibleRows, totalHeight: virtualTotalHeight, onScroll } = virtualizer;
|
||
|
|
```
|
||
|
|
|
||
|
|
#### useVirtualRows.ts
|
||
|
|
```typescript
|
||
|
|
// Added safety guard for invalid indices
|
||
|
|
const visibleRows = computed<VirtualRow[]>(() => {
|
||
|
|
if (startIndex < 0 || endIndex < startIndex) {
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
// ... rest of computation
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
### Debug Techniques Used
|
||
|
|
|
||
|
|
1. **Force re-render**: `table.classList.add('x'); requestAnimationFrame(() => table.classList.remove('x'))`
|
||
|
|
- If rows change after force-re-render, reactivity IS working but scroll event isn't triggering updates
|
||
|
|
|
||
|
|
2. **Check virtualizer state**: Debug info showed `Visible Rows: 10` and `Total Rows: 10` - all rows were intentionally rendered
|
||
|
|
|
||
|
|
3. **Calculate expected behavior**:
|
||
|
|
- viewport = 306px
|
||
|
|
- total content = 660px (10 rows)
|
||
|
|
- max scroll = 354px
|
||
|
|
- overscan = 5 on each side
|
||
|
|
|
||
|
|
### Lessons Learned
|
||
|
|
|
||
|
|
1. In Vue 3 `<script setup>`, always destructure refs that need to be used in templates
|
||
|
|
2. Virtual scrolling benefit is only visible when `total_rows > viewport + (overscan * row_height)`
|
||
|
|
3. Vue 3 auto-unwraps top-level refs but NOT refs nested in objects
|
||
|
|
4. `console.log` in Vue event handlers doesn't appear in browser console - Vue intercepts events
|
||
|
|
5. Programmatic scroll (`scrollTop = x`) doesn't fire scroll events - need to manually dispatch
|
||
|
|
|
||
|
|
### Files Modified
|
||
|
|
- `packages/base/data/list-table-v2/list-table-v2.vue`
|
||
|
|
- `packages/base/data/list-table-v2/useVirtualRows.ts`
|