代码演示
如何引入
<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 | number | semiGlobalDefault("ScrollList", "bodyHeight") |
| footer | 底部内容;传入 footer 插槽时以插槽为准。 | string | semiGlobalDefault("ScrollList", "footer") |
| header | 头部内容;传入 header 插槽时以插槽为准。 | string | semiGlobalDefault("ScrollList", "header") |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| 无 |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| default | 列表中的 ScrollItem。 | any |
| footer | 自定义底部内容。 | any |
| header | 自定义头部内容。 | any |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| 无 |
class、style 与 aria-* 等原生属性经 attrs 落在根元素上。
ScrollItem
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| cycled | 是否无限循环。wheel 模式下列表首尾相接地无限滚动;两种模式下方向键都在首尾循环。 | boolean | semiDefault("ScrollItem", "cycled", false) |
| list | 列表内容。 | T[] | semiGlobalDefault("ScrollItem", "list") |
| mode | 模式,可选 normal 或 wheel。 | "normal" | "wheel" | semiDefault("ScrollItem", "mode", "wheel") |
| motion | 是否开启滚动动画。 | boolean | semiDefault("ScrollItem", "motion", true) |
| selectedIndex | 选中项的索引,配合 v-model:selectedIndex 使用;没有非受控模式。 | number | semiGlobalDefault("ScrollItem", "selectedIndex") |
| transform | 对选中项文案的变换,没有 text 的项参数为 undefined;未传时显示 text,没有 text 时显示 value。数据项自带的 transform 优先。 | Type((value: T["value"], text?: string | undefined) => string) | undefined |
| type | 标识该列,供 TimePicker、DatePicker 等组件使用,不面向使用方。 | string | number | semiGlobalDefault("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-bg | var(--semi-transition_duration-none) | 滚动列表选中选项-背景颜色-动画持续时间 |
| $transition_function-scrollList_selected_item-bg | var(--semi-transition_function-easeOut) | 滚动列表选中选项-背景颜色-过渡曲线 |
| $transition_delay-scrollList_selected_item-bg | 0ms | 滚动列表选中选项-背景颜色-延迟时间 |
| $color-scrollList-bg | var(--semi-color-bg-3) | 滚动列表背景色 |
| $color-scrollList-border | var(--semi-color-border) | 滚动列表描边颜色 |
| $color-scrollList_header-bg | transparent | 滚动列表 header 背景色 |
| $color-scrollList_header-title | var(--semi-color-text-0) | 滚动列表标题颜色 |
| $color-scrollList_item-bg | transparent | 滚动列表选项背景色 |
| $color-scrollList_item-text | var(--semi-color-text-0) | 滚动列表选项文字颜色 |
| $color-scrollList_disabled_item-text | var(--semi-color-disabled-text) | 滚动列表选项背景色 - 禁用 |
| $color-scrollList_item-text-hover | var(--semi-color-fill-1) | 滚动列表选项文字颜色 - 悬浮 |
| $color-scrollList_item-bg-active | var(--semi-color-fill-2) | 滚动列表选项文字颜色 - 选中 |
| $color-scrollList_selected_item-bg | var(--semi-color-primary-light-default) | 滚动列表选中选项背景颜色 |
| $color-scrollList_selected_item-text | var(--semi-color-text-0) | 滚动列表选中选项文字颜色 |
| $color-scrollList_selected_item-icon | var(--semi-color-text-2) | 滚动列表选中选项图标颜色 |
| $color-scrollList_footer-border | var(--semi-color-border) | 滚动列表底部描边颜色 |
| $height-scrollList | 300px | |
| $height-scrollList_item | 36px | |
| $width-scrollList_item-border | $border-thickness-control | |
| $width-scrollList_item_sel_svg | 16px | |
| $width-scrollList_item_wheel_selector-border | $border-thickness-control | |
| $height-scrollList_line | 1px | |
| $width-scrollList_footer-border | $border-thickness-control | |
| $spacing-scrollList_header-paddingY | 0 | |
| $spacing-scrollList_header-paddingX | 16px | |
| $spacing-scrollList_header_title-paddingY | $spacing-base | |
| $spacing-scrollList_header_title-paddingX | 0 | |
| $spacing-scrollList_body-paddingY | 0 | |
| $spacing-scrollList_body-paddingX | 16px | |
| $spacing-scrollList_item_ul-padding | 0 | |
| $spacing-scrollList_item_ul-margin | 0 | |
| $spacing-scrollList_item_ul-paddingBottom | ($height-scrollList - $height-scrollList_item) * 0.5 | |
| $spacing-scrollList_item_sel_svg-marginRight | 12px | |
| $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-padding | 10px | |
| $radius-scrollList | var(--semi-border-radius-medium) | |
| $font-scrollList_header_title-fontWeight | $font-weight-bold | |
| $font-scrollList_item_wheel_item_selected-fontWeight | $font-weight-bold | |
| $shadow-scrollList | var(--semi-shadow-elevated) |