iter(g14): 演示站目录支持关键字过滤

This commit is contained in:
HIsheR
2026-10-26 10:29:03 +08:00
parent 4ffc6545ef
commit b3c3bc70a4
2 changed files with 26 additions and 2 deletions
+22 -2
View File
@@ -51,14 +51,34 @@ import {
} from '@ui-arch/ui';
import type { RowKey } from '@ui-arch/ui';
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随) ***/
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随);顶部搜索框按标题过滤 ***/
function buildToc(toc: HTMLElement, content: HTMLElement): void {
const secs = Array.from(content.querySelectorAll<HTMLElement>('section.sec'));
if (!secs.length) return; // 卫语句:无区块不建目录
const links = secs.map((sec) =>
h('a', { class: 'toc-link', href: `#${sec.id}`, 'data-for': sec.id }, sec.querySelector('h2')?.textContent ?? sec.id),
);
toc.append(...links);
const search = h('input', { class: 'toc-search', type: 'search', placeholder: '过滤组件…', 'aria-label': '过滤组件目录' }) as HTMLInputElement;
const empty = h('p', { class: 'toc-empty' }, '无匹配项'); // 过滤后一条不剩时的提示
empty.hidden = true;
/*** 按标题子串过滤目录项;空关键字恢复全量 ***/
const apply = (): void => {
const q = search.value.trim().toLowerCase();
let hit = 0;
for (const link of links) {
const on = !q || (link.textContent ?? '').toLowerCase().includes(q);
link.hidden = !on; // 隐藏项同时退出 Tab 序(hidden 自带)
if (on) hit++;
}
empty.hidden = hit > 0;
};
search.addEventListener('input', apply);
search.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.key !== 'Escape' || !search.value) return; // 卫语句:无内容时 Esc 交给默认行为
search.value = '';
apply();
});
toc.append(search, ...links, empty);
const io = new IntersectionObserver(
(entries) => {
for (const en of entries) {