代码演示

如何引入

jsx
import { Transfer } from '@kousum/semi-ui-vue';

基本使用

数据项需传入 value、label、key

分组

将 type 设为 groupList

分组的 dataSource,一级子元素必须拥有 title 以及 children 属性,结构参考 <GroupItem>

暂不支持多层嵌套

自定义筛选逻辑,自定义选项数据渲染

使用filter自定义搜索逻辑,返回 true 时表示当前项符合筛选规则,保留当前项在列表中的显示,返回 false 则表示不符合,当前项会被隐藏。
当 type 为 treeList时,如需要自定义搜索逻辑,需设置 filter 为 true,并通过 treePropsfilterTreeNode 设置自定义的搜索函数。
使用renderSourceItem,你可以自定义左侧每一条源数据的渲染结构。
使用renderSelectedItem 你可以自定义右侧每一条已选项的渲染结构。

css
.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) => ReactNode
renderSelectedHeader: (props: SelectedHeaderProps) => ReactNode
参数类型如下:

ts
type SourceHeaderProps = {
    num: number; // 数据总数或筛选结果数目
    showButton: boolean; // 是否展示全选/取消全选按钮
    allChecked: boolean; // 当前数据是否已全选
    onAllClick: () => void // 点击全选/取消全选按钮后应调用的函数
}

type SelectedHeaderProps = {
    num: number; // 已选中数据总数
    showButton: boolean; // 是否展示清空按钮
    onClear: () => void // 点击清空按钮后应调用的函数
}

使用示例如下

完全自定义渲染

Semi 提供了 renderSourcePanelrenderSelectedPanel 入参,允许你完全自定义左右侧两个面板的渲染结构
通过该功能,你可以直接复用 Transfer 内部的逻辑能力,实现高度自定义样式结构的Transfer组件 renderSourcePanel: (sourcePanelProps: SourcePanelProps) => ReactNode
SourcePanelProps包含以下参数,你可以从中获取数据来渲染出你的 Panel 结构

ts
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) => ReactNode
SelectedPanelProps包含以下参数

ts
interface SelectedPanelProps {
  length: number; // 已选项的数量
  onClear: () => void; // 点击清空时应调用的回调函数
  onRemove: (item: Item) => void; // 删除单个选项时应调用的函数
  onSortEnd: ({ oldIndex, newIndex}) => void; // 对结果重新排序时应调用的函数
  selectedData: Array<Item>; // 所有已选项集合
}
scss
.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

  • 搜索框添加 role search
  • 右侧选中列表添加 role list,选中项添加 role listitem

API 参考

Transfer Props

属性说明类型默认值版本
className样式类名string
dataSource数据源Array<Item>|Array<GroupItem>|Array<TreeItem>[]
defaultValue默认已选中值Array<string|number>
disabled是否禁用booleanfalse
draggable是否开启拖拽排序booleanfalse
emptyContent自定义空状态的提示文本,search 为无搜索结果时展示的文本,left 为左侧无源数据时的文本,right 为无勾选数据时的提示文本{left: ReactNode; right: ReactNode; search: ReactNode;}
filter自定义筛选逻辑, 当为 false 时,不展示搜索框,传入函数可自定义搜素逻辑。当 type 为 treeList时,如需要自定义搜索逻辑,需设置 filter 为 true,并通过 treePropsfilterTreeNode 设置自定义的搜索函数。boolean | (input:string, item: Item) => booleantrue
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) => ReactNode2.29.0
renderSelectedItem自定义右侧单个已选项的渲染(item: { onRemove, sortableHandle } & Item) => ReactNode
renderSelectedPanel自定义右侧已选面板的渲染(selectedPanelProps) => ReactNode1.11.0
renderSourceHeader自定义左侧面板头部信息的渲染(props: SourceHeaderProps) => ReactNode2.29.0
renderSourceItem自定义左侧单个候选项的渲染(item: { onChange, checked } & Item) => ReactNode
renderSourcePanel自定义左侧候选面板的渲染(sourcePanelProps) => ReactNode1.11.0
showPath当 type 为treeList时,控制右侧选中项是否显示选择路径booleanfalse1.20.0
style内联样式CSSProperties
treeProps当 type 为treeList时,可作为 TreeProps 传入左侧的 Tree 组件TreeProps1.20.0
typeTransfer 类型,可选listgroupListtreeListstring'list'1.20.0
value已选中值,传入该项时,将作为受控组件使用Array<string|number>

Item Interface

属性说明类型默认值
className样式类名string
disabled是否禁用booleanfalse
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 调用实现某些特殊交互

NameDescription
search(value: string)可通过 ref 调用该方法进行搜索,该搜索值会被置给 Input。

设计变量