2026-06-08 21:57:18 +08:00
<!DOCTYPE html>
< html data-bs-theme = "dark" >
< head >
< meta charset = "utf-8" >
< title > List Mega Test (Virtual Scroll Stress Test)< / title >
< script src = "./lib/state.js" > < / script >
< script src = "./lib/bootstrap.js" > < / script >
< script src = "./lib/base.js" > < / script >
< style >
body { height: 100vh; background: #111; color: #eee; }
.test-container { display: grid; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr); gap: 20px; height: 100%; padding: 20px; box-sizing: border-box; }
.list-card { display: flex; flex-direction: column; overflow: hidden; border: 1px solid #444; border-radius: 8px; background: #222; }
.list-card h5 { padding: 10px; margin: 0; background: #333; border-bottom: 1px solid #444; font-size: 14px; }
< / style >
< / head >
< body >
< div class = "test-container" >
< div class = "list-card" >
2026-06-28 12:00:46 +08:00
< h5 class = "d-flex align-items-center justify-content-between" >
< span > 1. Standard List (Normal)< / span >
< div class = "d-flex gap-2" >
< input type = "text" id = "searchInput" class = "form-control form-control-sm" style = "width: 120px;" placeholder = "Search..." $ bind = "State.stdFilter" >
< select id = "sortSelect" class = "form-select form-select-sm" style = "width: 100px;" $ bind = "State.stdOrder" >
< option value = "" > No Sort< / option >
< option value = "label" > Label Asc< / option >
< option value = "-label" > Label Desc< / option >
< / select >
< / div >
< / h5 >
< List id = "listStd" class = "flex-fill" $ . state . list = "State.stdItems" $ filter = "State.stdFilter || ''" $ order = "State.stdOrder" auto-select > < / List >
2026-06-08 21:57:18 +08:00
< / div >
< div class = "list-card" >
2026-06-28 12:00:46 +08:00
< h5 class = "d-flex align-items-center justify-content-between" >
< span > 2. Group List (Mode: Group)< / span >
< input type = "text" id = "grpSearchInput" class = "form-control form-control-sm" style = "width: 120px;" placeholder = "Search..." $ bind = "State.grpFilter" >
< / h5 >
< List id = "listGrp" mode = "group" class = "flex-fill" $ . state . list = "State.grpItems" $ . state . groups = "State.groups" $ filter = "State.grpFilter || ''" > < / List >
2026-06-08 21:57:18 +08:00
< / div >
< div class = "list-card" >
2026-06-28 12:00:46 +08:00
< h5 class = "d-flex align-items-center justify-content-between" >
< span > 3. Tree List (Mode: Tree + Collapsible)< / span >
< input type = "text" id = "treeSearchInput" class = "form-control form-control-sm" style = "width: 120px;" placeholder = "Search..." $ bind = "State.treeFilter" >
< / h5 >
< List id = "listTree" mode = "tree" collapsible class = "flex-fill" $ . state . list = "State.treeItems" $ filter = "State.treeFilter || ''" > < / List >
2026-06-08 21:57:18 +08:00
< / div >
< div class = "list-card" >
< h5 > 4. FAST Virtual List (10,000 Items + Dynamic Height)< / h5 >
< List id = "listFast" fast class = "flex-fill" $ . state . list = "State.bigItems" auto-select >
<!-- 自定义插槽:必须保留 list - group - item 类和 $onupdate 钩子 -->
< template slot = "item" >
< div $ onupdate = "this.onItemUpdate(index, thisNode)"
$class="list-group-item list-group-item-action d-flex flex-column w-100 py-2 \${this.state?.selectedItem===item.id?'active':''}"
$onclick="this.selectItem(item,index)">
< div class = "d-flex align-items-center" >
< i class = "bi bi-person-circle me-2 text-primary" > < / i >
< span class = "fw-bold" $ text = "item.label" > < / span >
< span class = "ms-auto badge bg-dark text-muted" $ text = "'#' + item.id" > < / span >
< / div >
< div class = "small text-secondary mt-1" style = "white-space: normal; line-height: 1.4" $ text = "item.summary" > < / div >
< / div >
< / template >
< / List >
< / div >
< / div >
< script >
// 1. 准备标准数据
const stdItems = [];
for(let i=1; i< =50; i++) stdItems.push({ id: i, label: 'Item ' + i, summary: 'This is standard item ' + i });
const groups = [
{ id: 'g1', label: 'Engineering', summary: 'Technical staff' },
{ id: 'g2', label: 'Marketing', summary: 'Growth team' },
{ id: 'g3', label: 'Sales', summary: 'Revenue drivers' }
];
const grpItems = [];
for(let i=1; i< =100; i++) {
grpItems.push({ id: i, label: 'Member ' + i, group: i % 3 === 0 ? 'g1' : (i % 3 === 1 ? 'g2' : 'g3') });
}
const treeItems = [
{ id: 'root1', label: 'Company HQ', parent: '' },
{ id: 'dept1', label: 'R& D Division', parent: 'root1' },
{ id: 'team1', label: 'Framework Team', parent: 'dept1' },
{ id: 'team2', label: 'UI Team', parent: 'dept1' },
{ id: 'dept2', label: 'Operations', parent: 'root1' },
{ id: 'team3', label: 'Cloud Ops', parent: 'dept2' },
{ id: 'root2', label: 'Overseas Branch', parent: '' },
{ id: 'dept3', label: 'Asia Pacific', parent: 'root2' }
];
// 2. 准备 10,000 条极端高度差异数据
const bigItems = [];
const lorem = [
"Short summary.",
"Medium length summary that might take two lines in a narrow container to test dynamic height measurement accurately. We are checking if the VirtualScroll correctly captures this.",
"EXTREME HEIGHT TEST: " + new Array(15).fill("This is a very long line of text intended to force the container to expand significantly. ").join(" ") + " This block should be at least 200px-300px high depending on the width.",
"Normal sentence for baseline."
];
for(let i=1; i< =10000; i++) {
bigItems.push({
id: i,
label: 'Virtual Item ' + i,
summary: lorem[i % 4]
});
}
State.stdItems = stdItems;
State.groups = groups;
State.grpItems = grpItems;
State.treeItems = treeItems;
State.bigItems = bigItems;
< / script >
< / body >
< / html >