展示类

滚动列表

滚动列表。

代码演示

如何引入

<script setup lang="ts">
    import { ScrollList, ScrollItem } from '@fibrous/semi-ui-vue';
</script>

基本使用

滚动列表提供了一个类似于 iOS 操作系统的滚动选择模式,同时支持滚动至指定窗口位置选择与点击选择。

选中项用 v-model:selectedIndex 绑定,没有非受控模式;header、footer 是字符串 prop,需要自定义内容时使用同名插槽。

无限滚动列表
  • 上午
  • 下午
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
代码
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, ScrollItem, ScrollList, type ScrollItemSelectData } from '@fibrous/semi-ui-vue';

    const ampms = [{ value: '上午' }, { value: '下午' }];
    const hours = Array.from({ length: 12 }, (_, index) => ({ value: index + 1 }));
    const minutes = Array.from({ length: 60 }, (_, index) => ({ value: index, disabled: index % 3 === 0 }));

    const selectIndex1 = ref(1);
    const selectIndex2 = ref(1);
    const selectIndex3 = ref(1);

    const onSelectHour = (data: ScrollItemSelectData) => {
        console.log('You have choose the hour for: ', data.value);
    };

    const onSelectMinute = (data: ScrollItemSelectData) => {
        console.log('You have choose the minute for: ', data.value);
    };

    const handleClose = () => {
        console.log('close');
    };
</script>

<template>
    <ScrollList header="无限滚动列表" :style="{ border: 'unset', boxShadow: 'unset' }">
        <ScrollItem v-model:selectedIndex="selectIndex1" aria-label="上午或下午" :cycled="false" :list="ampms" mode="wheel" :type="1" />
        <ScrollItem v-model:selectedIndex="selectIndex2" aria-label="小时" cycled :list="hours" mode="wheel" :type="2" @select="onSelectHour" />
        <ScrollItem v-model:selectedIndex="selectIndex3" aria-label="分钟" cycled :list="minutes" mode="wheel" :type="3" @select="onSelectMinute" />
        <template #footer>
            <Button size="small" type="primary" @click="handleClose">Ok</Button>
        </template>
    </ScrollList>
</template>

API 参考

ScrollList

Props

属性说明类型默认值
bodyHeight列表主体的高度。string | numbersemiGlobalDefault("ScrollList", "bodyHeight")
footer底部内容;传入 footer 插槽时以插槽为准。stringsemiGlobalDefault("ScrollList", "footer")
header头部内容;传入 header 插槽时以插槽为准。stringsemiGlobalDefault("ScrollList", "header")

Events

事件说明回调参数
无

Slots

插槽说明作用域参数
default列表中的 ScrollItem。any
footer自定义底部内容。any
header自定义头部内容。any

Exposes

名称说明类型
无

class、style 与 aria-* 等原生属性经 attrs 落在根元素上。

ScrollItem

Props

属性说明类型默认值
cycled是否无限循环。wheel 模式下列表首尾相接地无限滚动;两种模式下方向键都在首尾循环。booleansemiDefault("ScrollItem", "cycled", false)
list列表内容。T[]semiGlobalDefault("ScrollItem", "list")
mode模式,可选 normal 或 wheel。"normal" | "wheel"semiDefault("ScrollItem", "mode", "wheel")
motion是否开启滚动动画。booleansemiDefault("ScrollItem", "motion", true)
selectedIndex选中项的索引,配合 v-model:selectedIndex 使用;没有非受控模式。numbersemiGlobalDefault("ScrollItem", "selectedIndex")
transform对选中项文案的变换,没有 text 的项参数为 undefined;未传时显示 text,没有 text 时显示 value。数据项自带的 transform 优先。Type((value: T["value"], text?: string | undefined) => string)undefined
type标识该列,供 TimePicker、DatePicker 等组件使用,不面向使用方。string | numbersemiGlobalDefault("ScrollItem", "type")

Events

事件说明回调参数
update:selectedIndex选中项变化时触发,用于 v-model:selectedIndex。[index: number]
select选中某项时触发,参数是该项数据加上列的 type 和该项在 list 中的 index。Type[data: ScrollItemSelectData<T>]

Slots

插槽说明作用域参数
无

Exposes

名称说明类型
无

aria-label、aria-labelledby、aria-describedby 落在列表(role="listbox")上,class、style 等其余属性落在根元素上。

ItemData

属性说明类型默认值
disabled该项是否被禁止选择boolean
text每一项的文案string
transform该项处于选中状态时的变换,返回值会作为文案进行显示,ScrollItem 组件如果同时传入会优先选择 ItemData 中的 transform 方法;未传时显示 text,没有 text 时显示 value(value: any, text: string | undefined) => string
value每一项的值any

Methods

通过 ScrollItem 的模板 ref 调用,用于在容器尺寸变化等场景下重新对齐选中项

名称说明
scrollToIndex(selectedIndex?: number, duration?: number)将列表滚动到当前选中项。selectedIndex 暂不生效,目标始终是最近一次选中的项;duration 为滚动动画时长,单位毫秒,默认 120

Accessibility

ARIA

  • 传入 aria-label 或 aria-labelledby 时,ScrollList 的根元素带 role="group"
  • ScrollItem 是 role="listbox",支持传入 aria-label, 指定该列标签
  • ScrollItem 使用 aria-disabled 表示该项目是否被禁用
  • ScrollItem 使用 aria-selected 表示该项目是否被选中
  • cycled 的 wheel 列里用来填满滚轮的副本带 aria-hidden="true",读屏只读到本体选项

键盘和焦点

  • 每列是一个 listbox,用 Tab 聚焦,焦点留在列表上,选中项通过 aria-activedescendant 指示;选中跟随焦点,每次选中都会触发选中回调
  • 上箭头 选中上一项,下箭头 选中下一项,被禁用的项会被跳过;Home 选中第一项,End 选中最后一项
  • 设置 cycled 后,两种模式下方向键都在首尾循环;未设置时到首尾即停
  • 输入字符按文案开头匹配并选中对应项,连续输入同一字符时依次选中下一个匹配项

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$transition_duration-scrollList_selected_item-bgvar(--semi-transition_duration-none)滚动列表选中选项-背景颜色-动画持续时间
$transition_function-scrollList_selected_item-bgvar(--semi-transition_function-easeOut)滚动列表选中选项-背景颜色-过渡曲线
$transition_delay-scrollList_selected_item-bg0ms滚动列表选中选项-背景颜色-延迟时间
$color-scrollList-bgvar(--semi-color-bg-3)滚动列表背景色
$color-scrollList-bordervar(--semi-color-border)滚动列表描边颜色
$color-scrollList_header-bgtransparent滚动列表 header 背景色
$color-scrollList_header-titlevar(--semi-color-text-0)滚动列表标题颜色
$color-scrollList_item-bgtransparent滚动列表选项背景色
$color-scrollList_item-textvar(--semi-color-text-0)滚动列表选项文字颜色
$color-scrollList_disabled_item-textvar(--semi-color-disabled-text)滚动列表选项背景色 - 禁用
$color-scrollList_item-text-hovervar(--semi-color-fill-1)滚动列表选项文字颜色 - 悬浮
$color-scrollList_item-bg-activevar(--semi-color-fill-2)滚动列表选项文字颜色 - 选中
$color-scrollList_selected_item-bgvar(--semi-color-primary-light-default)滚动列表选中选项背景颜色
$color-scrollList_selected_item-textvar(--semi-color-text-0)滚动列表选中选项文字颜色
$color-scrollList_selected_item-iconvar(--semi-color-text-2)滚动列表选中选项图标颜色
$color-scrollList_footer-bordervar(--semi-color-border)滚动列表底部描边颜色
$height-scrollList300px
$height-scrollList_item36px
$width-scrollList_item-border$border-thickness-control
$width-scrollList_item_sel_svg16px
$width-scrollList_item_wheel_selector-border$border-thickness-control
$height-scrollList_line1px
$width-scrollList_footer-border$border-thickness-control
$spacing-scrollList_header-paddingY0
$spacing-scrollList_header-paddingX16px
$spacing-scrollList_header_title-paddingY$spacing-base
$spacing-scrollList_header_title-paddingX0
$spacing-scrollList_body-paddingY0
$spacing-scrollList_body-paddingX16px
$spacing-scrollList_item_ul-padding0
$spacing-scrollList_item_ul-margin0
$spacing-scrollList_item_ul-paddingBottom($height-scrollList - $height-scrollList_item) * 0.5
$spacing-scrollList_item_sel_svg-marginRight12px
$spacing-scrollList_item_wheel_list_outer-paddingRight$height-scrollList_item * 0.5
$spacing-scrollList_item_wheel_list_shade_pre-marginTop-1 * ($height-scrollList_item * 0.5 + $border-thickness-control)
$spacing-scrollList_item_wheel_list_shade_post-marginTop$height-scrollList_item * 0.5 + $border-thickness-control
$spacing-scrollList_footer-padding10px
$radius-scrollListvar(--semi-border-radius-medium)
$font-scrollList_header_title-fontWeight$font-weight-bold
$font-scrollList_item_wheel_item_selected-fontWeight$font-weight-bold
$shadow-scrollListvar(--semi-shadow-elevated)