展示类

折叠列表

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

代码演示

如何引入

import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-solid';

折叠模式 - 默认

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

items 只放数据,不放节点。每个展示项由 visibleItemRenderer 返回的元素渲染;溢出项由 overflowRenderer 渲染,collapse 模式下只渲染一个溢出节点,参数是放不下的项。

0100


代码
import { createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-solid';
import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-solid';

interface Item {
    icon: typeof IconAlarm;
    key: string;
}

const items: Item[] = [
    { icon: IconAlarm, key: 'alarm' },
    { icon: IconBookmark, key: 'bookmark' },
    { icon: IconCamera, key: 'camera' },
    { icon: IconDuration, key: 'duration' },
    { icon: IconEdit, key: 'edit' },
    { icon: IconFolder, key: 'folder' },
];

const renderOverflow = (overflowItems: Item[]) => (overflowItems.length ? <Tag style={{ flex: '0 0 auto', 'font-variant-numeric': 'tabular-nums' }}>+{overflowItems.length}</Tag> : null);

const renderItem = (item: Item) => (
    <Tag color="blue" style={{ 'margin-right': '8px', flex: '0 0 auto' }}>
        <Dynamic component={item.icon} style={{ 'margin-right': '4px' }} />
        {item.key}
    </Tag>
);

export default function OverflowListDemo() {
    const [width, setWidth] = createSignal(100);

    return (
        <div>
            <Slider
                aria-label="Container width"
                step={1}
                value={width()}
                onChange={(value) => {
                    if (typeof value === 'number') setWidth(value);
                }}
            />
            <br />
            <br />
            <div style={{ width: `${width()}%` }}>
                <OverflowList items={items} overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
            </div>
        </div>
    );
}

折叠模式 - 方向

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

0100


代码
import { createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-solid';
import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-solid';

interface Item {
    icon: typeof IconAlarm;
    key: string;
}

const items: Item[] = [
    { icon: IconAlarm, key: 'alarm' },
    { icon: IconBookmark, key: 'bookmark' },
    { icon: IconCamera, key: 'camera' },
    { icon: IconDuration, key: 'duration' },
    { icon: IconEdit, key: 'edit' },
    { icon: IconFolder, key: 'folder' },
];

const renderOverflow = (overflowItems: Item[]) => (overflowItems.length ? <Tag style={{ 'margin-right': '8px', flex: '0 0 auto', 'font-variant-numeric': 'tabular-nums' }}>+{overflowItems.length}</Tag> : null);

const renderItem = (item: Item) => (
    <Tag color="blue" style={{ 'margin-right': '8px', flex: '0 0 auto' }}>
        <Dynamic component={item.icon} style={{ 'margin-right': '4px' }} />
        {item.key}
    </Tag>
);

export default function OverflowListDemo() {
    const [width, setWidth] = createSignal(100);

    return (
        <div>
            <Slider
                aria-label="Container width"
                step={1}
                value={width()}
                onChange={(value) => {
                    if (typeof value === 'number') setWidth(value);
                }}
            />
            <br />
            <br />
            <div style={{ width: `${width()}%` }}>
                <OverflowList items={items} collapseFrom="start" overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
            </div>
        </div>
    );
}

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

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

0100


代码
import { createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-solid';
import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-solid';

interface Item {
    icon: typeof IconAlarm;
    key: string;
}

const items: Item[] = [
    { icon: IconAlarm, key: 'alarm' },
    { icon: IconBookmark, key: 'bookmark' },
    { icon: IconCamera, key: 'camera' },
    { icon: IconDuration, key: 'duration' },
    { icon: IconEdit, key: 'edit' },
    { icon: IconFolder, key: 'folder' },
];

const renderOverflow = (overflowItems: Item[]) => (overflowItems.length ? <Tag style={{ flex: '0 0 auto', 'font-variant-numeric': 'tabular-nums' }}>+{overflowItems.length}</Tag> : null);

const renderItem = (item: Item) => (
    <Tag color="blue" style={{ 'margin-right': '8px', flex: '0 0 auto' }}>
        <Dynamic component={item.icon} style={{ 'margin-right': '4px' }} />
        {item.key}
    </Tag>
);

export default function OverflowListDemo() {
    const [width, setWidth] = createSignal(100);

    return (
        <div>
            <Slider
                aria-label="Container width"
                step={1}
                value={width()}
                onChange={(value) => {
                    if (typeof value === 'number') setWidth(value);
                }}
            />
            <br />
            <br />
            <div style={{ width: `${width()}%` }}>
                <OverflowList items={items} minVisibleItems={3} overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
            </div>
        </div>
    );
}

滚动模式

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

滚动模式下 overflowRenderer 的参数是 [start, end] 两组项,分别为滚出可见区域之前与之后的项,返回值为两侧各一个节点。

0100


+0
alarm
bookmark
camera
duration
edit
folder
+0
代码
import { createSignal, type JSX } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-solid';
import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-solid';

interface Item {
    icon: typeof IconAlarm;
    key: string;
}

const items: Item[] = [
    { icon: IconAlarm, key: 'alarm' },
    { icon: IconBookmark, key: 'bookmark' },
    { icon: IconCamera, key: 'camera' },
    { icon: IconDuration, key: 'duration' },
    { icon: IconEdit, key: 'edit' },
    { icon: IconFolder, key: 'folder' },
];

const renderHiddenCount = (hiddenItems: Item[]) => <Tag style={{ 'margin-right': '8px', 'margin-left': '8px', flex: '0 0 auto', 'font-variant-numeric': 'tabular-nums' }}>+{hiddenItems.length}</Tag>;

const renderOverflow = ([start, end]: [Item[], Item[]]): [JSX.Element, JSX.Element] => [renderHiddenCount(start), renderHiddenCount(end)];

const renderItem = (item: Item) => (
    <Tag color="blue" style={{ 'margin-right': '8px', flex: '0 0 auto' }}>
        <Dynamic component={item.icon} style={{ 'margin-right': '4px' }} />
        {item.key}
    </Tag>
);

export default function OverflowListDemo() {
    const [width, setWidth] = createSignal(100);

    return (
        <div>
            <Slider
                aria-label="Container width"
                step={1}
                value={width()}
                onChange={(value) => {
                    if (typeof value === 'number') setWidth(value);
                }}
            />
            <br />
            <br />
            <div style={{ width: `${width()}%` }}>
                <OverflowList items={items} renderMode="scroll" overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
            </div>
        </div>
    );
}

API 参考

Props

属性说明类型默认值
collapseFromcollapse 模式的折叠方向,可选 start 或 end。'start' | 'end'"end"
itemKey每项 key 的字段名,或取 key 的函数;默认读取 key 字段,没有时取该项在 items 中的位置。Typestring | number | ((item: T) => string | number)-
items渲染项目,只放数据,不放节点,节点由 visibleItemRenderer 渲染;scroll 模式要求每项含 key 字段(或由 itemKey 指定的字段)。TypeArray<T>[]
minVisibleItemscollapse 模式下最少展示的项数,这些项即使放不下也不会折叠。number0
onIntersectscroll 模式下各项的相交状态变化时调用,参数以 key 为索引,值为对应项的 IntersectionObserverEntry。Type(res: { [key: string]: IntersectionObserverEntry }) => void-
onOverflowcollapse 模式下溢出项变化时调用,全部放得下时以空数组调用。Type(overflowItems: Array<T>) => void-
onVisibleStateChangescroll 模式下各项的显示或隐藏状态变化时调用,参数为以 key 为索引的 Map。Type(visibleState: Map<string, boolean>) => void-
overflowRenderDirectionscroll 模式下两侧溢出节点的位置,可选 both、start 或 end;供 Tabs 使用,不面向使用方。'both' | 'start' | 'end'"both"
overflowRenderer渲染溢出项。collapse 模式下参数为放不下的项,返回一个溢出节点;scroll 模式下参数为 [start, end] 两组项,返回两侧各一个节点。Type((overflowItems: Array<T>) => JSX.Element) | ((overflowItems: [Array<T>, Array<T>]) => [JSX.Element, JSX.Element])Type() => null
renderMode渲染模式,可选 collapse 或 scroll。'collapse' | 'scroll'"collapse"
thresholdscroll 模式下触发相交回调的可见比例阈值。number0.75
visibleItemRenderer渲染单个可见项并返回该项的元素,参数 index 为该项在 items 中的位置。scroll 模式下该元素会被观察,并写入 data-scrollkey。Type(item: T, index: number) => JSX.ElementType() => null
wrapperClassNamescroll 模式下滚动 wrapper 的类名。string-
wrapperPropsscroll 模式下滚动 wrapper 的其他属性,例如承载可见项的 role。TypeJSX.HTMLAttributes<HTMLDivElement>-
wrapperStylescroll 模式下滚动 wrapper 的样式,可传样式对象或样式字符串。JSX.CSSProperties | string-

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

Accessibility

ARIA

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