Transfer 穿梭框
双栏穿梭选择框,数据在左(源)右(目标)两个列表之间移动。
基础用法
基础穿梭框
Transfer 的数据通过 data 属性传入。 数据需要是一个对象数组,每个对象有以下属性:key 为数据的唯一性标识,label 为显示文本,disabled 表示该项数据是否禁止被操作。 目标列表中的数据项会同步到绑定至 v-model 的变量,值为数据项的 key 所组成的数组。 当然,如果希望在初始状态时目标列表不为空,可以像本例一样为 v-model 绑定的变量赋予一个初始值。
自定义
可以对列表标题文案、按钮文案、数据项的渲染函数、列表顶部的勾选状态文案、列表底部的内容区等进行自定义。 使用 titles、button-texts、render-content 和 format 属性分别对列表标题文案、按钮文案、数据项的渲染函数和列表顶部的勾选状态文案进行自定义。 数据项的渲染还可以使用 default 作用域插槽进行自定义。 对于列表底部的内容区,提供了两个具名插槽:left-footer 和 right-footer。 此外,如果希望某些数据项在初始化时就被勾选,可以使用 left-default-checked 和 right-default-checked 属性。 最后,本例还展示了 change 事件的用法。 注意,由于 JSFiddle 不支持 JSX 语法,故该示例无法在 JSFiddle 运行。 但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。
通过 render-content 自定义数据项
通过 scoped slot 自定义数据项
数据项属性别名
默认情况下,Transfer 仅能识别数据项中的 key、label 和 disabled 字段。 如果你的数据的字段名不同,可以使用 props 属性为它们设置别名。 本例中的数据源没有 key 和 label 字段,在功能上与它们相同的字段名为 value 和 desc。 因此可以使用 props 属性为 key 和 label 设置别名。
自定义空内容
使用 left-empty 和 right-empty 插槽来自定义每个面板在列表为空或未找到筛选结果时显示的内容。
暂无数据
功能
可搜索过滤
在数据很多的情况下,可以对数据进行搜索和过滤。 设置 filterable 为 true 即可开启搜索模式。 默认情况下,若数据项的 label 属性包含搜索关键字,则会在搜索结果中显示。 你也可以使用 filter-method 定义自己的搜索逻辑。 filter-method 接收一个方法,当搜索关键字变化时,会将当前的关键字、每个数据项以及该数据项所属面板(left / right)传给该方法。 若方法返回 true,则会在搜索结果中显示对应的数据项。
分页与面板尺寸
通过 show-pagination 属性设置是否开启分页功能,page-size 控制每页条数。 通过 panel-width 属性设置 Transfer 左右面板的宽度,panel-height 属性设置面板高度。 列表顶部的勾选状态文案还可以通过 render-checked 渲染函数完全自定义,其入参为 (checked, total, panelType)。
单向穿梭框 1.3.4
设置 one-way 为 true 即可开启单向模式,只允许「左 → 右」移动,适用于一次性的选择场景。 该模式下右侧列表项以纯文本展示,每项尾部有 × 按钮,点击 × 即可把该项移回左侧。
列表 23 项
简单模式 1.3.4
设置 simple 为 true 即可开启简单模式,隐藏中间的穿梭按钮,直接单击列表项完成移动。 该模式下左右列表项均以文本行展示:左侧整行可点,单击即右移;右侧点击 × 即左移。 禁用项(数据自带 disabled 或命中 disabled-right)不可移动,也不显示 ×。
列表 110 项
列表 22 项
简单模式下没有中间的穿梭按钮,单击列表项即可移动。
禁用右侧数据项 1.3.4
通过 disabled-right 传入一个 key 数组,命中的右侧列表项将被禁用(不可勾选、不可删除、不可点击移动),其效果与数据项自带的 disabled 字段等效叠加。 该属性只作用于右侧列表,左侧列表的行为不受影响。 单向 / 简单模式及 target-clearable 下,被禁用的项也不会出现 ×。
带选择器的穿梭框 1.3.4
设置 selectable 为 true 后,左右列表顶部都会显示一个可清空的单选下拉框,可按所属分组快速筛选。 选项由数据源按 parentKey 去重后的 parentLabel 生成,左右面板的筛选相互独立。 选中某个分组后,该面板列表只保留 parentKey 命中的项;该筛选与 filterable 的关键字过滤相互独立,两者同时生效时取交集。 开启该模式后,数据源中的每一项都必须带有 parentKey 与 parentLabel 字段,否则会抛出异常提示。
虚拟滚动 1.3.4
大数据量时仅展示可视区域内的条目。
设置 virtual-scroll 为 true 即可开启虚拟滚动。 可通过 item-size 自定义条目高度,默认 32(与主题变量 --w3-transfer-item-height 一致)。 可与 filterable 搭配使用,过滤后滚动位置自动复位到顶部。
列表区扩展
树型穿梭框 1.3.4
source / target 插槽用于整体替换面板的列表区(原复选框列表不再显示),适合树型、表格型等自定义外壳的场景。
插槽参数:
data:经过搜索过滤后的当前面板数据selectedKeys:当前已勾选的 key 数组onSelect(cur, { checkedKeys }):回写勾选结果,签名与w-tree的check事件一致,可直接绑定
树型场景通常只需要替换左侧,右侧保持默认列表。本例设置 check-strictly(父子不关联):
- 父、子节点都是独立的数据项,
data中两者都包含,勾选互不影响 - 父节点也可以单独勾选、单独穿梭到右侧
- 已穿梭到右侧的节点(无论父或子)在左侧树中禁用,移回后自动恢复,避免重复穿梭
搜索过滤由业务接管:通过 left-search 事件拿到关键字后调用树自身的 filter 方法,插槽内树的数据完全由业务掌握。
用 source 插槽把左侧列表区整体替换为 w-tree,右侧保持默认列表。
树型穿梭框(父子关联) 1.3.4
与上一例的区别有两点。
一是勾选联动:不设置 check-strictly,勾选父节点会联动勾选其全部子节点,onSelect 收到的 checkedKeys 就是树组件计算后的完整集合。
二是 data 的取舍:父节点能否穿梭到右侧由 data 决定,与勾选联动无关——父子关联场景下父节点只作分组容器,data 只提供叶子节点,父节点不会出现在右侧;若业务需要父节点也参与穿梭,把它一并放进 data 即可。
树本身由插槽参数 data(当前源列表数据)重建:
- 仍在源列表中的叶子正常可选
- 已穿梭到右侧的叶子禁用,联动勾选父节点时也不会被计入
checkedKeys - 从右侧移回后对应节点自动恢复可选
不设置 check-strictly 的父子关联形态:勾选父节点联动勾选全部子节点,data 只提供叶子节点。
表格型穿梭框 1.3.4
show-table 配合 source / target 插槽,把左右两个面板的列表区整体替换为 w-table(列表以表格形态呈现时,头部的全选复选框与勾选计数已无意义)。
设置 show-table 为 true 后:
- 面板头部只显示数据项数量(如
12 项),不显示全选复选框与勾选计数 - 头部标题区可通过
left-header-title/right-header-title插槽自定义(本例左侧为「医嘱(共 12 条)」) - 列表区的上下内边距归零,表格可贴边填充
表格的 select-all / selection-change 回传的是行对象数组,需要转换后调用 onSelect(null, { checkedKeys })。注意 source / target 与逐项自定义的 default 插槽是两个不同层级:前者替换整个列表区,后者只替换单个数据项的内容,二者不可混用。
左右列表区均替换为 w-table,头部只显示数据项数量,通过 selection-change 回写勾选结果。
医嘱(共 12 条) 10 项
列表 22 项
事件处理器要写成函数表达式
@selection-change="handleSelect(onSelect)" 这类只做调用、不使用 $event 的写法会被 Vue3 编译为行内语句($event => handleSelect(onSelect)),返回值被丢弃,勾选结果不会回写。 请改成 @selection-change="handleSelect($event, onSelect)" 或箭头函数 @selection-change="(rows) => ..."。
Transfer API
Attributes
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| model-value / v-model | 选中项绑定值 | object | [] |
| data | Transfer 的数据源 | object | [] |
| filterable | 是否可搜索 | boolean | false |
| filter-placeholder | 搜索框占位符 | string | — |
| filter-method | 自定义搜索方法,第三个参数为当前面板归属 | Function | — |
| target-order | 右侧列表元素的排序策略: 若为 original,则保持与数据源相同的顺序; 若为 push,则新加入的元素排在最后; 若为 unshift,则新加入的元素排在最前 | enum | original |
| titles | 自定义列表标题 | object | [] |
| button-texts | 自定义按钮文案 | object | [] |
| render-content | 自定义数据项渲染函数 | object | — |
| format | 列表顶部勾选状态文案 | object | {} |
| props | 数据源的字段别名 | object | — |
| left-default-checked | 初始状态下左侧列表的已勾选项的 key 数组 | object | [] |
| right-default-checked | 初始状态下右侧列表的已勾选项的 key 数组 | object | [] |
| validate-event | 是否触发表单验证 | boolean | true |
| show-pagination | 是否显示分页 | boolean | false |
| page-size | 每页显示条数 | number | 10 |
| panel-width | 自定义面板宽度 | array | ['200px', '200px'] |
| panel-height | 自定义面板高度 | string | '278px' |
| render-checked | 左、右列表顶部的勾选状态文案渲染 Function,返回的字符串按 HTML 渲染 | Function | — |
| one-way 1.3.4 | 是否为单向模式。开启后仅允许「左 → 右」移动,右侧条目以纯文本展示,可通过 × 单项移除 | boolean | false |
| simple 1.3.4 | 是否为简单模式。开启后隐藏中间按钮区,列表项单击即移动 | boolean | false |
| target-clearable 1.3.4 | 右侧列表项悬浮时是否在尾部显示 × 删除按钮 | boolean | false |
| selectable 1.3.4 | 是否在列表顶部显示按 parentKey 过滤的下拉选择器,左右面板各自独立筛选。开启后数据项必须包含 parentKey 与 parentLabel,否则抛出异常 | boolean | false |
| show-table 1.3.4 | 是否为表格模式。开启后面板头部只显示数据项数量;表格本体需业务通过 source / target 插槽自行提供 | boolean | false |
| disabled-right 1.3.4 | 右侧列表中需要禁用的项的 key 数组,与数据项自带的 disabled 等效叠加。只作用于右侧列表 | object | [] |
| virtual-scroll 1.3.4 | 是否开启虚拟滚动,大数据量时仅展示可视区域内的条目 | boolean | false |
| item-size 1.3.4 | 虚拟滚动的条目高度,与主题变量 --w3-transfer-item-height 保持一致 | number | 32 |
Events
| 事件名 | 说明 | 类型 |
|---|---|---|
| change | 右侧列表元素变化时触发 | Function |
| left-check-change | 左侧列表元素被用户选中 / 取消选中时触发 | Function |
| right-check-change | 右侧列表元素被用户选中 / 取消选中时触发 | Function |
| left-page-change | 左侧列表分页变化时触发 | Function |
| right-page-change | 右侧列表分页变化时触发 | Function |
| left-search 1.3.4 | 左侧列表搜索框每输入一个字符时触发,值为当前输入 | Function |
| right-search 1.3.4 | 右侧列表搜索框每输入一个字符时触发,值为当前输入 | Function |
Slots
| 插槽名 | 说明 |
|---|---|
| default | 自定义单个数据项的内容,参数为 { option } |
| left-footer | 左侧列表底部的内容 |
| right-footer | 右侧列表底部的内容 |
| left-empty | 左侧面板为空或没有数据符合筛选条件时的内容 |
| right-empty | 右侧面板为空或没有数据符合筛选条件时的内容 |
| left-header-title 1.3.4 | 左侧面板头部标题区内容 |
| right-header-title 1.3.4 | 右侧面板头部标题区内容 |
| source 1.3.4 | 整列表区替换左侧面板的列表区,参数为 { data, selectedKeys, onSelect } |
| target 1.3.4 | 整列表区替换右侧面板的列表区,参数为 { data, selectedKeys, onSelect } |
请注意 source / target 与 default 是两个不同的层级
default只自定义单个数据项的内容,列表区(含复选框、滚动容器)仍由组件提供;source/target替换整个列表区,用于树型、表格型等自定义外壳的场景,此时列表区完全由插槽内容提供;- 两者都仅在提供对应插槽时才生效,未提供时列表区 DOM 与不提供时完全一致。
插槽参数说明:data 为搜索过滤后的当前面板数据;selectedKeys 为当前已勾选的 key 数组;onSelect(cur, { checkedKeys }) 用于回写勾选状态,其签名与 w-tree 的 check 事件一致,可直接绑定。
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| clearQuery | 清空某个面板的搜索关键词 | Function |
| leftPanel | 左侧面板 ref | object |
| rightPanel | 右侧面板 ref | object |
Transfer Panel API
Exposes
| 名称 | 描述 | 类型 |
|---|---|---|
| query | 过滤关键词 | string |
| selectQuery | 选择器的过滤关键词 | string |
| selectOptions | 选择器去重后的选项列表 | object |
Type Declarations
Show declarations
import type { h as H, VNode } from 'vue'
type TransferKey = string | number
type TransferDirection = 'left' | 'right'
type TransferDataItem = Record<string, any>
type renderContent = (h: typeof H, option: TransferDataItem) => VNode | VNode[]
interface TransferFormat {
noChecked?: string
hasChecked?: string
}
interface TransferPropsAlias {
label?: string
key?: string
disabled?: string
}Copyright 2025 Winning Health 版权所有

