资讯详情

资讯详情

Element Plus Transfer 穿梭框组件完全指南:从基础用法到源码级原理剖析

Element Plus Transfer 穿梭框组件完全指南从基础用法到源码级原理剖析【免费下载链接】element-plus A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus导读穿梭框Transfer是管理型后台系统中高频使用的数据转移组件它通过左右两个面板配合中间操作按钮让用户直观地在可选数据与已选数据之间移动条目。本文以 Element PlusVue 3 组件库官方文档 Transfer 文档 为主体逐项讲解其数据模型、筛选、自定义、属性别名、虚拟滚动等能力并结合仓库内 transfer 组件源码 与各 composables 实现揭示底层的数据切分、移动策略、事件派发与虚拟列表原理帮助你既会用、又懂其实现。一、基础用法数据模型与 v-model 约定Transfer 的核心设计是数据源驱动左侧面板展示未选中的条目右侧面板展示已选中的条目二者共同由一份data数组和绑定到v-model的目标 key 数组推导而来。1.1 data 的数据结构要求data必须是对象数组且每个对象需要包含三个约定字段字段含义key数据项的唯一标识也是v-model数组中的元素label面板中展示的文本disabled该数据项是否禁用禁用项不可勾选、不可移动官方基础示例 basic.vue 展示了完整用法template el-transfer v-modelvalue :datadata / /template script langts setup import { ref } from vue interface Option { key: number label: string disabled: boolean } const generateData () { const data: Option[] [] for (let i 1; i 15; i) { data.push({ key: i, label: Option ${i}, disabled: i % 4 0, // 每 4 项禁用一个演示 disabled 效果 }) } return data } const data refOption[](generateData()) const value ref([]) // 初始右侧为空 /script1.2 v-model 的同步语义右侧列表的条目与v-model绑定的变量保持同步该变量的值是一个目标 key 数组Arraystring | number默认值为[]。因此若希望右侧面板初始就有数据只需把对应数据项的key预先放入v-model数组用户点击中间按钮移动条目时组件会通过update:model-value事件回写新数组见 transfer.ts 中modelValue的声明v-model数组仅存储 key不存储完整对象这是保持数据单一来源data属性的关键设计。1.3 源码视角左右面板数据如何推导组件并没有维护左侧数据和右侧数据两份副本而是通过 useComputedData 实时计算// 左侧 data 中 key 不在 modelValue 里的条目 const sourceData computed(() props.data.filter( (item) !props.modelValue.includes(item[propsAlias.value.key]) ) ) // 右侧 data 中 key 在 modelValue 里的条目 const targetData computed(() { ... })也就是说data永远是全量数据左右两栏只是它的两个投影projection这保证了右侧数据变化即 v-model 变化的单向数据流。该推导逻辑在 transfer.vue 中被接入组件主体。二、筛选模式Filterable内置过滤与自定义过滤当数据量较大时可开启filterable属性让用户在面板顶部输入关键字即时过滤。2.1 内置过滤规则在 useCheck.ts 中可以看到内置过滤的实现默认情况下只要数据项的label包含搜索关键字不区分大小写就会被保留若label缺失则退回到用key匹配const filteredData computed(() { return props.data.filter((item) { if (isFunction(props.filterMethod)) { return props.filterMethod(panelState.query, item) } else { const label String( item[propsAlias.value.label] || item[propsAlias.value.key] ) return label.toLowerCase().includes(panelState.query.toLowerCase()) } }) })2.2 自定义过滤方法 filter-method内置规则无法满足需求时可通过filter-method传入自定义函数。每当关键字变化时组件会把搜索关键字和每一个数据项传给该方法对某个数据项返回true即表示命中type filterMethod (query: string, item: Recordstring, any) boolean例如按编号或组合字段过滤el-transfer v-modelvalue :datadata filterable :filter-methodfilterMethod / script langts setup // 只匹配 label 以关键字开头的项或 key 恰好等于数字关键字 const filterMethod (query: string, item: Recordstring, any) { return item.label.startsWith(query) || String(item.key) query } /script同时可用filter-placeholder自定义搜索输入框的占位文本未设置时使用 i18n 默认文案el.transfer.filterPlaceholder见 transfer.vue。注意开启虚拟滚动后每次查询变化组件会调用虚拟列表的scrollToItem(0)将滚动位置重置到顶部use-check.ts。三、自定义面板标题、按钮、渲染内容与页脚Transfer 提供了从标题、按钮文本到条目渲染、页脚内容的完整自定义能力。3.1 标题与按钮文本titles[string, string]分别指定左、右面板标题默认使用 i18n 文案el.transfer.titles.0/el.transfer.titles.1button-texts[string, string]分别指定移到左侧移到右侧两个按钮的文字。仅在同时提供两个文本时按钮才会显示文字源码中以hasButtonTexts buttonTexts.length 2判断见 transfer.vue。3.2 自定义条目渲染render-content 与默认插槽有两种方式定制每个条目的展示方式一render-content渲染函数。签名在 transfer.ts 中定义type renderContentT extends TransferDataItem TransferDataItem ( h: typeof H, option: T ) VNode | VNode[]使用 JSX 示例需要项目正确配置 JSX/TSX 相关依赖script langtsx setup import { h } from vue const renderContent (h, option) { return span{option.label} - i stylecolor:#909399{option.key}/i/span } /script template el-transfer v-modelvalue :datadata :render-contentrenderContent / /template方式二默认插槽scoped slot。插槽作用域为{ option: TransferDataItem }el-transfer v-modelvalue :datadata template #default{ option } span{{ option.label }}编号 {{ option.key }}/span /template /el-transfer在 transfer.vue 中二者优先级是render-content优先于默认插槽默认插槽优先于内置的纯文本span渲染。3.3 列表头部状态文本 formatformat对象用于定制面板头部已勾选/总数的显示文本类型为 TransferFormatinterface TransferFormat { noChecked?: string hasChecked?: string }支持两个占位符${checked}已勾选数量与${total}面板总数。实现见 use-check.ts当同时提供noChecked与hasChecked时会替换占位符生成文案否则退化为默认的已勾选数/总数形式。例如el-transfer v-modelvalue :datadata :format{ noChecked: 共 ${total} 项, hasChecked: 已选 ${checked} / 共 ${total} 项, } /3.4 页脚插槽与初始勾选left-footer/right-footer两个具名插槽分别注入左右面板底部内容模板中透传给两个transfer-panel见 transfer.vueleft-default-checked/right-default-checkedArraystring | number用于指定左右面板初始勾选的 key 数组。注意源码中对defaultChecked的 watch 会在数据变化时重新计算勾选集合只保留可勾选且存在于当前面板的 keyuse-check.ts。3.5 空内容自定义插槽 ^(2.9.0)自 2.9.0 起提供left-empty与right-empty插槽用于定制面板为空或过滤无结果时的展示内容对应示例 empty-content.vueel-transfer v-modelvalue :datadata template #left-empty左侧暂无数据/template template #right-empty右侧空空如也快去选择吧/template /el-transfer四、属性别名Props Aliases适配任意字段命名实际业务数据往往不叫key/label/disabled此时无需改造数据直接用props属性声明别名即可。类型为 TransferPropsAliasinterface TransferPropsAlias { label?: string key?: string disabled?: string }官方示例 prop-alias.vue 中数据项使用value与desc字段el-transfer v-modelvalue :props{ key: value, label: desc, } :datadata / script langts setup interface Option { value: number desc: string disabled: boolean } // data 中每项形如 { value: 1, desc: Option 1, disabled: false } /script实现上usePropsAlias 以{ label: label, key: key, disabled: disabled }为默认值再用传入的props浅合并覆盖因此别名只需声明有差异的字段。整个组件内部数据推导、过滤、勾选、移动统一通过item[propsAlias.value.key]等表达式访问字段这是所有自定义都能生效的底层前提。五、虚拟滚动大数据量下的性能方案 ^(2.14.3)当数据量达到上千条例如 2000 条时普通渲染会带来明显卡顿。Transfer 自 2.14.3 起支持虚拟滚动el-transfer v-modelvalue :datadata virtual-scroll :item-size30 /对应示例 virtual-scroll.vue 中一次渲染了 2000 条数据开启后仅渲染可视区域内的条目。5.1 相关属性属性类型默认值说明virtual-scrollbooleanfalse是否启用虚拟滚动item-sizenumber30虚拟滚动时每项的高度px默认 30px5.2 源码实现要点从 transfer-panel.vue 与 use-check.ts 可以看到虚拟滚动复用了仓库内 virtual-list 组件 的FixedSizeList定高列表面板通过useElementSize监听勾选容器的实际高度作为虚拟列表的可视区高度勾选状态仍由面板内部的checkboxGroupRef管理保证虚拟滚动下勾选行为与普通模式一致过滤查询变化时调用virtualListRef.value?.scrollToItem(0)回到顶部use-check.ts。由于虚拟列表依赖item-size精确计算滚动位置自定义item-size时必须与实际行高保持一致否则会出现条目错位。六、目标列表排序策略 target-ordertarget-order控制右侧目标列表条目的排列顺序取值original | push | unshift默认original取值行为original右侧始终按data原始顺序排列默认push新移入的条目追加到右侧底部unshift新移入的条目插入到右侧顶部源码层面targetData的推导在 use-computed-data.ts 中分流original模式下直接对data按modelValue过滤push/unshift模式下则按modelValue的顺序逐个从dataObj以 key 为索引的数据映射表取值。而移动动作在 use-move.ts 中实现addToRight先收集勾选且尚未在目标中的 key再依据targetOrder决定拼接位置最后调用_emit统一派发事件。七、API 参考属性、事件、插槽与 Exposes以下内容完整对应官方文档 Transfer API 章节。7.1 Transfer Attributes名称说明类型默认值model-value / v-model绑定值目标 key 数组Arraystring \| number[]data数据源Recordstring, any[][]filterable是否可筛选booleanfalsefilter-placeholder筛选输入框占位符string—filter-method自定义筛选方法(query: string, item: Recordstring, any) boolean—target-order目标列表排序策略original保持数据源顺序、push新项追加到底部、unshift新项插入到顶部original \| push \| unshiftoriginaltitles自定义面板标题[string, string][]button-texts自定义按钮文本[string, string][]render-content自定义数据项渲染函数renderContent—format列表头部勾选状态文本TransferFormat{}props数据源属性别名TransferPropsAlias—left-default-checked左侧面板初始勾选的 key 数组Arraystring \| number[]right-default-checked右侧面板初始勾选的 key 数组Arraystring \| number[]validate-event是否触发表单校验booleantruevirtual-scroll ^(2.14.3)是否启用虚拟滚动booleanfalseitem-size ^(2.14.3)虚拟滚动时每项高度pxnumber30以上默认值在 transfer.ts 的buildProps中均有明确定义如targetOrder通过values约束枚举、itemSize默认 30。7.2 Transfer Events名称说明类型change右侧列表数据变化时触发(value: TransferKey[], direction: TransferDirection, movedKeys: TransferKey[]) voidleft-check-change左侧任意条目勾选状态变化时触发(value: TransferKey[], movedKeys?: TransferKey[]) voidright-check-change右侧任意条目勾选状态变化时触发(value: TransferKey[], movedKeys?: TransferKey[]) void事件校验器定义在 transfer.tschange事件中direction只能是left | rightmovedKeys为本次实际移动的 key 数组。勾选类事件的movedKeys是新选中集合与旧选中集合的对称差由面板在 use-check.ts 的 watch 中计算再经 use-checked-change.ts 转发给上层。el-transfer v-modelvalue :datadata change(value, direction, movedKeys) console.log(value, direction, movedKeys) left-check-change(value, movedKeys) console.log(left, value, movedKeys) /7.3 Transfer Slots名称说明作用域类型default自定义数据项内容{ option: TransferDataItem }left-footer左侧面板页脚内容—right-footer右侧面板页脚内容—left-empty ^(2.9.0)左侧面板为空或过滤无结果时内容—right-empty ^(2.9.0)右侧面板为空或过滤无结果时内容—7.4 Transfer Exposes通过模板 ref 可访问组件实例的公开方法/引用名称说明类型clearQuery清除指定面板的筛选关键字(which: TransferDirection) voidleftPanel左侧面板 refRefTransferPanelInstancerightPanel右侧面板 refRefTransferPanelInstance用法示例script langts setup import { ref } from vue import type { TransferInstance } from element-plus const transferRef refTransferInstance() // 清除左侧面板的搜索关键字 transferRef.value?.clearQuery(left) /script template el-transfer reftransferRef v-modelvalue :datadata filterable / /template7.5 Transfer Panel ExposesleftPanel/rightPanel指向的TransferPanelInstance暴露一个query属性即该面板当前的筛选关键字string可通过它读取或设置面板搜索词。八、类型声明与表单集成8.1 完整类型声明组件对外公开的类型在 transfer.ts 中集中定义可直接从element-plus导入使用import type { h as H, VNode } from vue type TransferKey string | number type TransferDirection left | right type TransferDataItem Recordstring, any type renderContentT extends TransferDataItem TransferDataItem ( h: typeof H, option: T ) VNode | VNode[] interface TransferFormat { noChecked?: string hasChecked?: string } interface TransferPropsAlias { label?: string key?: string disabled?: string }8.2 与表单校验的集成Transfer 实现了validate-event默认true可无缝嵌入el-form。在 transfer.vue 中组件通过useFormItem取得父级表单上下文并在modelValue变化时调用formItem?.validate?.(change)watch( () props.modelValue, () { if (props.validateEvent) { formItem?.validate?.(change).catch(NOOP) } } )因此你可以在表单 rules 中为穿梭框配置校验规则如必须至少选择一项当用户在面板间移动条目时校验会自动触发。九、测试与可验证依据组件行为在 transfer.test.tsx 中有完整覆盖含筛选、移动、事件、属性别名、虚拟滚动等用例是理解各 API 实际语义的最佳参考。安装与引入方式与其他 Element Plus 组件一致import { ElTransfer } from element-plus并按需引入样式element-plus/theme-chalk中的 transfer 样式或使用完整样式包。结语Transfer 是一个小身材、大能力的组件单向数据流 数据源投影的设计让v-model语义简单可靠filter-method、render-content、props别名、format与多具名插槽共同撑起高自由度的定制空间而虚拟滚动与target-order则分别解决了大数据渲染和排序策略两个实战痛点。掌握这些 API 及其源码实现你就能在复杂业务中灵活驾驭数据穿梭场景。【免费下载链接】element-plus A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →