展示类

折叠列表

OverflowList 是一个行为组件,用于展示列表,并支持自适应来展示尽可能多的项目。因过长而溢出项目将折叠为一个元素。当检测到调整大小时,可见项将被重新计算。

代码演示

如何引入

<script lang="ts">
    import { OverflowList } from '@fibrae/semi-ui-svelte';
</script>

折叠模式 - 默认

通过 renderMode="collapse" (默认) 来实现内容的折叠。

items 只放数据,不放节点。每个展示项用 item snippet 渲染,参数 { item, index };溢出项用 overflow snippet 渲染,参数 { items, position },collapse 模式只在有溢出项时渲染一次,items 是放不下的项。

0 100


代码
<script lang="ts">
    import type { Component } from 'svelte';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrae/semi-icons-svelte';
    import { OverflowList, Slider, Tag } from '@fibrae/semi-ui-svelte';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    let width = $state<number | number[]>(100);
</script>

<div>
    <Slider aria-label="Container width" bind:value={width} step={1} />
    <br />
    <br />
    <div style="width: {width}%">
        <OverflowList {items}>
            {#snippet item({ item })}
                {@const Icon = icons[item.key]}
                <Tag color="blue" style="margin-right: 8px; flex: 0 0 auto">
                    <Icon style="margin-right: 4px" />
                    <span>{item.key}</span>
                </Tag>
            {/snippet}
            {#snippet overflow({ items: hidden })}
                {#if hidden.length}
                    <Tag style="flex: 0 0 auto; font-variant-numeric: tabular-nums">+{hidden.length}</Tag>
                {/if}
            {/snippet}
        </OverflowList>
    </div>
</div>

折叠模式 - 方向

collapse 模式下支持 collapseFrom 设置折叠方向。

0 100


代码
<script lang="ts">
    import type { Component } from 'svelte';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrae/semi-icons-svelte';
    import { OverflowList, Slider, Tag } from '@fibrae/semi-ui-svelte';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    let width = $state<number | number[]>(100);
</script>

<div>
    <Slider aria-label="Container width" bind:value={width} step={1} />
    <br />
    <br />
    <div style="width: {width}%">
        <OverflowList collapseFrom="start" {items}>
            {#snippet item({ item })}
                {@const Icon = icons[item.key]}
                <Tag color="blue" style="margin-right: 8px; flex: 0 0 auto">
                    <Icon style="margin-right: 4px" />
                    <span>{item.key}</span>
                </Tag>
            {/snippet}
            {#snippet overflow({ items: hidden })}
                {#if hidden.length}
                    <Tag style="margin-right: 8px; flex: 0 0 auto; font-variant-numeric: tabular-nums">+{hidden.length}</Tag>
                {/if}
            {/snippet}
        </OverflowList>
    </div>
</div>

折叠模式 - 最小展示的数目

collapse 模式下支持 minVisibleItems 设置最小展示的数目。

0 100


代码
<script lang="ts">
    import type { Component } from 'svelte';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrae/semi-icons-svelte';
    import { OverflowList, Slider, Tag } from '@fibrae/semi-ui-svelte';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    let width = $state<number | number[]>(100);
</script>

<div>
    <Slider aria-label="Container width" bind:value={width} step={1} />
    <br />
    <br />
    <div style="width: {width}%">
        <OverflowList {items} minVisibleItems={3}>
            {#snippet item({ item })}
                {@const Icon = icons[item.key]}
                <Tag color="blue" style="margin-right: 8px; flex: 0 0 auto">
                    <Icon style="margin-right: 4px" />
                    <span>{item.key}</span>
                </Tag>
            {/snippet}
            {#snippet overflow({ items: hidden })}
                {#if hidden.length}
                    <Tag style="flex: 0 0 auto; font-variant-numeric: tabular-nums">+{hidden.length}</Tag>
                {/if}
            {/snippet}
        </OverflowList>
    </div>
</div>

滚动模式

通过 renderMode="scroll" 来使用滚动模式的折叠列表。如果需要 scrollIntoView,可以通过选择器: document.querySelector(`.item-cls[data-scrollkey="${key}"] 来选取。

滚动模式下 overflow 在两侧各渲染一次,position 为 start 或 end,items 是该侧滚出可见区域的项。每项被包进 display: contents 的 span,并在 item snippet 渲染出的第一个元素上写 data-scrollkey 并观察它,所以 item 必须输出元素,否则该项被跳过。

0 100


+0
alarm
bookmark
camera
duration
edit
folder
+0
代码
<script lang="ts">
    import type { Component } from 'svelte';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrae/semi-icons-svelte';
    import { OverflowList, Slider, Tag } from '@fibrae/semi-ui-svelte';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    let width = $state<number | number[]>(100);
</script>

<div>
    <Slider aria-label="Container width" bind:value={width} step={1} />
    <br />
    <br />
    <div style="width: {width}%">
        <OverflowList {items} renderMode="scroll">
            {#snippet item({ item })}
                {@const Icon = icons[item.key]}
                <Tag color="blue" style="margin-right: 8px; flex: 0 0 auto">
                    <Icon style="margin-right: 4px" />
                    <span>{item.key}</span>
                </Tag>
            {/snippet}
            {#snippet overflow({ items: hidden })}
                <Tag style="margin-right: 8px; margin-left: 8px; flex: 0 0 auto; font-variant-numeric: tabular-nums">+{hidden.length}</Tag>
            {/snippet}
        </OverflowList>
    </div>
</div>

API 参考

Props

属性说明类型默认值
collapseFromcollapse 模式的折叠方向,可选 start 或 end。'start' | 'end'"end"
item单个展示项内容的 snippet,参数 { item, index }:数据项及其在 items 中的位置。scroll 模式要求 snippet 渲染出元素,否则该项被跳过。TypeSnippet<[OverflowListItemSnippetProps<T>]>-
itemKey每项 key 的字段名,或取 key 的函数;默认读取 key 字段,没有时取该项在 items 中的位置。TypeOverflowListKey | ((item: T) => OverflowListKey)-
items渲染项目,只放数据,不放节点;scroll 模式要求每项含 key。T[]-
minVisibleItemscollapse 模式下最少展示的项数。number0
onIntersectscroll 模式下各项的相交状态变化时的回调。Type(res: Record<string, IntersectionObserverEntry>) => void-
onOverflowcollapse 模式下溢出项变化时的回调,全部放得下时参数为空数组。Type(overflowItems: T[]) => void-
onVisibleStateChangescroll 模式下各项的显示或隐藏状态变化时的回调。Type(visibleState: Map<string, boolean>) => void-
overflow溢出项内容的 snippet,参数 { items, position }。collapse 模式只在有溢出项时渲染一次,items 为放不下的项;scroll 模式在两侧各渲染一次,position 为 start 或 end,items 为该侧滚出可见区域的项。TypeSnippet<[OverflowListOverflowSnippetProps<T>]>-
overflowRenderDirectionscroll 模式下溢出节点的位置,可选 both、start 或 end;供 Tabs 使用,不面向使用方。'both' | 'start' | 'end'"both"
renderMode渲染模式,可选 collapse 或 scroll。'collapse' | 'scroll'"collapse"
thresholdscroll 模式下触发溢出回调的可见比例阈值。number0.75
wrapperClassNamescroll 模式下滚动 wrapper 的类名。string-
wrapperPropsscroll 模式下滚动 wrapper 的其他属性,例如承载可见项的 role。TypeHTMLAttributes<HTMLDivElement>-
wrapperStylescroll 模式下滚动 wrapper 的样式字符串。string-

class、style(字符串)与 aria-* 等原生属性落在根元素上;滚动 wrapper 的类名、样式和其他属性用 wrapperClassName、wrapperStyle、wrapperProps 传入。

Accessibility

ARIA

  • 传入 aria-label 或 aria-labelledby 时,根元素带 role="group",使这组项目有可读的名称;未传时根元素没有角色