Files
tools/vue/toolkit/src/composables/component/useVirtualList/demo.vue
T
robonen aa2938cb34 refactor(toolkit): type source any with proper types
Genuinely type composable any usages (useStepper/useStorage/useForm/
createEventHook/useSorted/etc.) as proper generics/unknown; keep idiomatic
any-function and overload-impl signatures with comments; skipped test -> .todo.
2026-06-15 16:55:07 +07:00

94 lines
2.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, ref, shallowRef } from 'vue';
import { useVirtualList } from './index';
// 10,000 rows — only the visible window (plus overscan) is ever in the DOM.
const total = 10000;
const items = shallowRef(
Array.from({ length: total }, (_, i) => ({
id: i,
label: `Row #${(i + 1).toString().padStart(5, '0')}`,
hue: (i * 37) % 360,
})),
);
const itemHeight = 44;
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(items, {
itemHeight,
overscan: 6,
});
const jumpTo = ref(5000);
function go() {
const index = Math.min(Math.max(jumpTo.value || 0, 0), total - 1);
scrollTo(index, { behavior: 'smooth', block: 'center' });
}
const visibleRange = computed(() => {
if (list.value.length === 0)
return '—';
const first = list.value[0]!.index;
const last = list.value[list.value.length - 1]!.index;
return `${first}${last}`;
});
</script>
<template>
<div class="demo-stack max-w-sm">
<div class="flex items-center justify-between">
<span class="demo-label">Virtual list</span>
<span class="demo-badge">
{{ total.toLocaleString() }} rows
</span>
</div>
<div
v-bind="containerProps"
class="demo-card h-64"
>
<div v-bind="wrapperProps">
<div
v-for="{ data, index } in list"
:key="index"
class="flex items-center gap-3 border-b border-border px-3"
:style="{ height: `${itemHeight}px` }"
>
<span
class="size-6 shrink-0 rounded-md border border-border"
:style="{ backgroundColor: `hsl(${data.hue} 65% 55%)` }"
/>
<span class="flex-1 truncate font-mono text-sm text-fg tabular-nums">{{ data.label }}</span>
<span class="text-xs text-fg-subtle">idx {{ index }}</span>
</div>
</div>
</div>
<div class="rounded-lg border border-border bg-bg-inset p-3 font-mono text-sm text-fg tabular-nums flex items-center justify-between">
<span class="text-fg-muted">rendered</span>
<span>{{ list.length }} nodes · idx {{ visibleRange }}</span>
</div>
<div class="flex items-end gap-2">
<label class="flex flex-1 flex-col gap-1">
<span class="demo-label">Scroll to index</span>
<input
v-model.number="jumpTo"
type="number"
:min="0"
:max="total - 1"
class="demo-input"
>
</label>
<button
type="button"
class="inline-flex items-center justify-center gap-1.5 rounded-lg border border-transparent bg-accent px-3 py-2 text-sm font-medium text-accent-fg transition hover:bg-accent-hover active:scale-[0.98] cursor-pointer"
@click="go"
>
Jump
</button>
</div>
</div>
</template>