代码演示
如何引入
import { Transfer } from '@kousum/semi-ui-vue';基本使用
数据项需传入 value、label、key
分组
将 type 设为 groupList
分组的 dataSource,一级子元素必须拥有 title 以及 children 属性,结构参考 <GroupItem>
暂不支持多层嵌套
自定义筛选逻辑,自定义选项数据渲染
使用filter自定义搜索逻辑,返回 true 时表示当前项符合筛选规则,保留当前项在列表中的显示,返回 false 则表示不符合,当前项会被隐藏。
当 type 为 treeList时,如需要自定义搜索逻辑,需设置 filter 为 true,并通过 treeProps 的 filterTreeNode 设置自定义的搜索函数。
使用renderSourceItem,你可以自定义左侧每一条源数据的渲染结构。
使用renderSelectedItem 你可以自定义右侧每一条已选项的渲染结构。
.components-transfer-demo-selected-item {
.semi-icon-close {
visibility: hidden;
color: var(--semi-color-tertiary);
}
&:hover {
.semi-icon-close {
visibility: visible;
}
}
}
.components-transfer-demo-selected-item,
.components-transfer-demo-source-item {
height: 52px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
&:hover {
background-color: var(--semi-color-fill-0);
}
.info {
margin-left: 8px;
flex-grow: 1;
}
.name {
font-size: 14px;
line-height: 20px;
}
.email {
font-size: 12px;
line-height: 16px;
color: var(--semi-color-text-2);
}
}禁用
拖拽排序
将 draggable设为 true,开启拖拽排序功能。v1.11.0 后支持
拖拽 + 自定义已选项渲染
将 draggable设为 true,开启拖拽排序功能;使用 renderSelectedItem 自定义右侧已选项渲染;
你可以将触发器定义为任意你想要的ReactNode,并且添加样式。将拖拽触发器,使用 sortableHandle 进行包裹即可(sortableHandle于 v 1.22.0 后提供),
自定义渲染面板头部信息
Semi 自 2.29.0 版本提供 renderSourceHeader, renderSelectedHeader 参数允许用户自定义渲染左右两个面板的头部信息。renderSourceHeader: (props: SourceHeaderProps) => ReactNoderenderSelectedHeader: (props: SelectedHeaderProps) => ReactNode
参数类型如下:
type SourceHeaderProps = {
num: number; // 数据总数或筛选结果数目
showButton: boolean; // 是否展示全选/取消全选按钮
allChecked: boolean; // 当前数据是否已全选
onAllClick: () => void // 点击全选/取消全选按钮后应调用的函数
}
type SelectedHeaderProps = {
num: number; // 已选中数据总数
showButton: boolean; // 是否展示清空按钮
onClear: () => void // 点击清空按钮后应调用的函数
}使用示例如下
完全自定义渲染
Semi 提供了 renderSourcePanel、renderSelectedPanel 入参,允许你完全自定义左右侧两个面板的渲染结构
通过该功能,你可以直接复用 Transfer 内部的逻辑能力,实现高度自定义样式结构的Transfer组件 renderSourcePanel: (sourcePanelProps: SourcePanelProps) => ReactNodeSourcePanelProps包含以下参数,你可以从中获取数据来渲染出你的 Panel 结构
interface SourcePanelProps {
value: Array<string|number>; // 所有选中项的key
loading: boolean; // 是否加载中
noMatch: boolean; // 是否没有符合当前搜索值匹配的项
filterData: Array<Item> // 匹配当前搜索值的项
sourceData: Array<Item>; // 所有项
allChecked: boolean; // 是否全部选中
showNumber: number; // 筛选结果数量
inputValue: string; // input搜索框的值
onSearch: (searchString: string) => any; // 搜索框变化时应调用的函数,入参为搜索值
onAllClick: () => void; // 左侧全部按钮点击时应调用的函数
onSelectOrRemove: (item: Item) => any; //选择、删除单个选项时应调用的函数,入参应为当前操作item
onSelect: (value:Array<string|number>)=>void; // 受控批量选中key
selectedItem: Map, // 所有已选项的集合
}renderSelectedPanel: (selectedPanelProps: SelectedPanelProps) => ReactNodeSelectedPanelProps包含以下参数
interface SelectedPanelProps {
length: number; // 已选项的数量
onClear: () => void; // 点击清空时应调用的回调函数
onRemove: (item: Item) => void; // 删除单个选项时应调用的函数
onSortEnd: ({ oldIndex, newIndex}) => void; // 对结果重新排序时应调用的函数
selectedData: Array<Item>; // 所有已选项集合
}.component-transfer-demo-custom-panel {
.sp-font {
color: rgba(var(--semi-grey-9), 1);
font-size: 12px;
font-weight: 500;
line-height: 20px;
}
.empty {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.panel-item {
flex-shrink: 0;
height: 56px;
border-radius: 4px;
padding: 8px 12px;
flex-wrap: wrap;
background-color: rgba(22, 24, 35, .03);
&-main {
flex-grow: 1;
}
p {
margin: 0 12px;
flex-basis: 100%;
}
.panel-item-remove {
cursor: pointer;
color: var(--semi-color-primary);
}
}
.panel-header {
padding: 10px 12px;
border: 1px solid rgba(22, 24, 35, .16);
border-radius: 4px 4px 0 0;
height: 38px;
box-sizing: border-box;
background-color: var(--semi-color-tertiary-light-default);
display: flex;
align-items: center;
justify-content: space-between;
.clear {
cursor: pointer;
color: var(--semi-color-primary);
}
}
.source-panel {
display: flex;
flex-direction: column;
width: 482px;
height: 353px;
.panel-main {
border: 1px solid var(--semi-color-border);
border-top: none;
.panel-list {
display: flex;
flex-wrap: wrap;
row-gap: 8px;
column-gap: 8px;
overflow-y: auto;
height: 214px;
margin-left: 12px;
margin-right: 12px;
padding-bottom: 8px;
}
}
.panel-controls {
margin: 10px 12px;
font-size: 12px;
line-height: 20px;
.semi-button {
margin-left: 8px;
font-size: 12px;
}
}
.panel-item {
width: 176px;
}
margin-right: 16px;
}
.selected-panel {
width: 200px;
height: 353px;
.panel-main {
display: flex;
flex-direction: column;
overflow-y: auto;
padding: 12px;
border: 1px solid var(--semi-color-border);
border-top: none;
height: 323px;
box-sizing: border-box;
row-gap: 8px;
}
}
}完全自定义渲染 、 拖拽排序
在完全自定义渲染的场景下,由于拖拽区的渲染也已由你完全接管,因此你不声明 draggable 亦可。 但你需要自行实现拖拽逻辑,你可以借助社区中拖拽类工具库 dnd-kit
另外,要支持拖拽排序,你需要在拖拽排序结束后,将 oldIndex、newIndex 作为入参,调用 onSortEnd
使用 dnd-kit 的示例如下,需要用到的核心依赖有 @dnd-kit/sortable, @dnd-kit/core,其中核心 hooks 为 useSortable,使用说明如下
1. 作用:通过唯一标志 id 获取拖拽过程中必要信息
2. 核心输入参数:
- id: 唯一标识, 以为数字或者字符串,但是不能为数字 0
3. 核心返回值说明:
- setNodeRef: 关联 dom 节点,使其成为一个可拖拽的项
- listeners: 包含 onKeyDown,onPointerDown 等方法,主要让节点可以进行拖拽
- transform:该节点被拖动时候的移动变化值
- transition:过渡效果
- active: 被拖拽节点的相关信息,包括 id树穿梭框
传入 type 为treeList,使用Tree组件作为自定义渲染列表。v1.20.0 提供
可通过treeProps(TreeProps)来覆盖默认树的属性,左侧树默认属性为
{
multiple:true,
disableStrictly:true,
leafOnly:true,
filterTreeNode:true,
searchRender:flase,
}Accessibility
ARIA
- 搜索框添加
rolesearch - 右侧选中列表添加
rolelist,选中项添加rolelistitem
API 参考
Transfer Props
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| className | 样式类名 | string | ||
| dataSource | 数据源 | Array<Item>|Array<GroupItem>|Array<TreeItem> | [] | |
| defaultValue | 默认已选中值 | Array<string|number> | ||
| disabled | 是否禁用 | boolean | false | |
| draggable | 是否开启拖拽排序 | boolean | false | |
| emptyContent | 自定义空状态的提示文本,search 为无搜索结果时展示的文本,left 为左侧无源数据时的文本,right 为无勾选数据时的提示文本 | {left: ReactNode; right: ReactNode; search: ReactNode;} | ||
| filter | 自定义筛选逻辑, 当为 false 时,不展示搜索框,传入函数可自定义搜素逻辑。当 type 为 treeList时,如需要自定义搜索逻辑,需设置 filter 为 true,并通过 treeProps 的 filterTreeNode 设置自定义的搜索函数。 | boolean | (input:string, item: Item) => boolean | true | |
| inputProps | 可用于自定义搜索框 Input,可配置属性参考 Input 组件,其中 value 和 onChange 参数在 Transfer 内部会被使用,用户请勿使用,如需通过外部数据进行搜索,可调用 Transfer 的 search 方法 | InputProps | ||
| loading | 是否正在加载左侧选项 | boolean | - | |
| onChange | 选中值发生变化时触发的回调, 拖拽排序变化后也会触发该回调 | (values: Array<string|number>, items: Array<Item>) => void | ||
| onDeselect | 取消勾选时的回调 | (item: Item) => void | ||
| onSearch | 搜索框输入内容变化时调用 | (inputValue: string) => void | ||
| onSelect | 勾选时的回调 | (item: Item) => void | ||
| renderSelectedHeader | 自定义右侧面板头部信息的渲染 | (props: SelectedHeaderProps) => ReactNode | 2.29.0 | |
| renderSelectedItem | 自定义右侧单个已选项的渲染 | (item: { onRemove, sortableHandle } & Item) => ReactNode | ||
| renderSelectedPanel | 自定义右侧已选面板的渲染 | (selectedPanelProps) => ReactNode | 1.11.0 | |
| renderSourceHeader | 自定义左侧面板头部信息的渲染 | (props: SourceHeaderProps) => ReactNode | 2.29.0 | |
| renderSourceItem | 自定义左侧单个候选项的渲染 | (item: { onChange, checked } & Item) => ReactNode | ||
| renderSourcePanel | 自定义左侧候选面板的渲染 | (sourcePanelProps) => ReactNode | 1.11.0 | |
| showPath | 当 type 为treeList时,控制右侧选中项是否显示选择路径 | boolean | false | 1.20.0 |
| style | 内联样式 | CSSProperties | ||
| treeProps | 当 type 为treeList时,可作为 TreeProps 传入左侧的 Tree 组件 | TreeProps | 1.20.0 | |
| type | Transfer 类型,可选list,groupList,treeList | string | 'list' | 1.20.0 |
| value | 已选中值,传入该项时,将作为受控组件使用 | Array<string|number> |
Item Interface
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| className | 样式类名 | string | |
| disabled | 是否禁用 | boolean | false |
| key | 必填,每个选项的唯一标识,不允许重复 | string | number | |
| label | 选项展示内容 | ReactNode | |
| style | 内联样式 | CSSProperties | |
| value | 选项代表的值 | string | number |
GroupItem Interface
GroupItem继承Item的所有属性
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| children | 该分组的元素 | Array<Item> | |
| title | 分组名称 | string |
TreeItem Interface
TreeItem 继承 Item 的所有属性
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| children | 子元素 | Array<TreeItem> |
Methods
绑定在组件实例上的方法,可以通过 ref 调用实现某些特殊交互
| Name | Description |
|---|---|
| search(value: string) | 可通过 ref 调用该方法进行搜索,该搜索值会被置给 Input。 |