From 7c0f340b8134d10129af86a77d9aad0a30aa4b5d Mon Sep 17 00:00:00 2001 From: jahnli Date: Wed, 1 Oct 2025 23:42:05 +0800 Subject: [PATCH] feat(transfer): add label-field and value-field props --- src/transfer/demos/enUS/index.demo-entry.md | 2 ++ src/transfer/demos/zhCN/index.demo-entry.md | 2 ++ src/transfer/src/Transfer.tsx | 12 ++++++- src/transfer/src/TransferList.tsx | 38 +++++++++++++++++---- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/transfer/demos/enUS/index.demo-entry.md b/src/transfer/demos/enUS/index.demo-entry.md index 16c1d78c4fa..21f910416a6 100644 --- a/src/transfer/demos/enUS/index.demo-entry.md +++ b/src/transfer/demos/enUS/index.demo-entry.md @@ -24,6 +24,7 @@ render-source-list.vue | default-value | `Array \| null` | `null` | Default value. | 2.32.0 | | disabled | `boolean` | `true` | Disabled state. | 2.32.0 | | filter | `(pattern: string, option: TransferOption, from: 'source' \| 'target') => boolean` | A basic label string match function. | 2.32.0, `from` 2.32.2 | +| label-field | `string` | `undefined` | The field name of the option `label`. | NEXT_VERSION | | options | `TransferOption[]` | `[]` | For configuration options, see the TransferOption Type below. | 2.32.0 | | render-source-label | `(props: { option: TransferOption }) => VNodeChild` | `undefined` | Customize source label rendering. | 2.32.0 | | render-target-label | `(props: { option: TransferOption }) => VNodeChild` | `undefined` | Customize target label rendering. | 2.32.0 | @@ -39,6 +40,7 @@ render-source-list.vue | target-filter-placeholder | `string` | `undefined` | Placeholder for the target items search box. | 2.32.0 | | target-title | `string \| (() => VNodeChild)` | `undefined` | Target items title. | 2.32.0, Render function since 2.40.0 | | value | `Array \| null` | `undefined` | Value when being set manually. | 2.32.0 | +| value-field | `string` | `undefined` | The field name of the option `value`. | NEXT_VERSION | | on-update:value | `(value: Array) => void` | `undefined` | Callback when the value changes. | 2.32.0 | | virtual-scroll | `boolean` | `false` | Enable virtual scrolling. | 2.32.0 | diff --git a/src/transfer/demos/zhCN/index.demo-entry.md b/src/transfer/demos/zhCN/index.demo-entry.md index f6eeee9a85d..2fa978a3768 100644 --- a/src/transfer/demos/zhCN/index.demo-entry.md +++ b/src/transfer/demos/zhCN/index.demo-entry.md @@ -26,6 +26,7 @@ value-debug.vue | default-value | `Array \| null` | `null` | 非受控模式下的默认值 | 2.32.0 | | disabled | `boolean` | `true` | 是否禁用 | 2.32.0 | | filter | `(pattern: string, option: TransferOption, from: 'source' \| 'target') => boolean` | 一个简单的标签字符串匹配函数 | 搜索时使用的过滤函数 | 2.32.0,`from` 2.32.2 | +| label-field | `string` | `undefined` | 选项 `label` 的字段名 | NEXT_VERSION | | options | `TransferOption[]` | `[]` | 配置选项内容,详情见 TransferOption Type | 2.32.0 | | render-source-label | `(props: { option: TransferOption }) => VNodeChild` | `undefined` | 自定义源标签 | 2.32.0 | | render-target-label | `(props: { option: TransferOption }) => VNodeChild` | `undefined` | 自定义目标标签 | 2.32.0 | @@ -41,6 +42,7 @@ value-debug.vue | target-filter-placeholder | `string` | `undefined` | 目标项搜索框中的占位符 | 2.32.0 | | target-title | `string \| (() => VNodeChild)` | `undefined` | 目标项标题 | 2.32.0,2.40.0 支持 render 函数 | | value | `Array \| null` | `undefined` | 受控模式下的值 | 2.32.0 | +| value-field | `string` | `undefined` | 选项 `value` 的字段名 | NEXT_VERSION | | on-update:value | `(value: Array) => void` | `undefined` | 值发生改变时的回调 | 2.32.0 | | virtual-scroll | `boolean` | `false` | 是否启用虚拟滚动 | 2.32.0 | diff --git a/src/transfer/src/Transfer.tsx b/src/transfer/src/Transfer.tsx index cac158eb33d..adbe9085e57 100644 --- a/src/transfer/src/Transfer.tsx +++ b/src/transfer/src/Transfer.tsx @@ -75,7 +75,15 @@ export const transferProps = { renderTargetList: Function as PropType, 'onUpdate:value': [Function, Array] as PropType>, onUpdateValue: [Function, Array] as PropType>, - onChange: [Function, Array] as PropType> + onChange: [Function, Array] as PropType>, + labelField: { + type: String, + default: 'label' + }, + valueField: { + type: String, + default: 'value' + } } as const export type TransferProps = ExtractPublicPropTypes @@ -337,6 +345,8 @@ export default defineComponent({ disabled={this.mergedDisabled} virtualScroll={this.virtualScroll} itemSize={this.itemSize} + labelField={this.labelField} + valueField={this.valueField} /> )} diff --git a/src/transfer/src/TransferList.tsx b/src/transfer/src/TransferList.tsx index 97bbf86dd2d..d3152413b3d 100644 --- a/src/transfer/src/TransferList.tsx +++ b/src/transfer/src/TransferList.tsx @@ -2,7 +2,7 @@ import type { PropType } from 'vue' import type { VirtualListInst } from 'vueuc' import type { ScrollbarInst } from '../../_internal' import type { Option } from './interface' -import { defineComponent, h, inject, ref } from 'vue' +import { computed, defineComponent, h, inject, ref } from 'vue' import { VirtualList } from 'vueuc' import { NScrollbar } from '../../_internal' import { NEmpty } from '../../empty' @@ -28,15 +28,32 @@ export default defineComponent({ type: Boolean, required: true }, + labelField: { + type: String, + default: 'label' + }, + valueField: { + type: String, + default: 'value' + }, source: Boolean }, - setup() { + setup(props) { const { mergedThemeRef, mergedClsPrefixRef } = inject(transferInjectionKey)! const scrollerInstRef = ref(null) const vlInstRef = ref(null) function syncVLScroller(): void { scrollerInstRef.value?.sync() } + + const optionsRef = computed(() => { + return props.options.map(option => ({ + label: option[props.labelField], + value: option[props.valueField], + disabled: option.disabled + })) + }) + function scrollContainer(): HTMLElement | null { const { value } = vlInstRef if (!value) @@ -58,7 +75,8 @@ export default defineComponent({ vlInstRef, syncVLScroller, scrollContainer, - scrollContent + scrollContent, + optionsRef } }, render() { @@ -71,8 +89,14 @@ export default defineComponent({ /> ) } - const { mergedClsPrefix, virtualScroll, source, disabled, syncVLScroller } - = this + const { + mergedClsPrefix, + virtualScroll, + source, + disabled, + syncVLScroller, + optionsRef + } = this return ( ) : (
- {options.map(option => ( + {optionsRef.map(option => (