x-next 1.16.1 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/AI_USAGE/catalog.md +3 -2
  2. package/AI_USAGE/components/alert-api.md +1 -1
  3. package/AI_USAGE/components/alert.md +33 -1
  4. package/AI_USAGE/components/bar-chart-api.md +1 -1
  5. package/AI_USAGE/components/bar-chart.md +1 -1
  6. package/AI_USAGE/components/boxicons.md +1 -1
  7. package/AI_USAGE/components/button-api.md +13 -16
  8. package/AI_USAGE/components/button.md +242 -31
  9. package/AI_USAGE/components/charts.md +1 -1
  10. package/AI_USAGE/components/checkbox-api.md +1 -1
  11. package/AI_USAGE/components/checkbox.md +1 -1
  12. package/AI_USAGE/components/color-picker-api.md +1 -1
  13. package/AI_USAGE/components/color-picker.md +1 -1
  14. package/AI_USAGE/components/config-provider-api.md +1 -1
  15. package/AI_USAGE/components/config-provider.md +1 -1
  16. package/AI_USAGE/components/date-picker-api.md +1 -1
  17. package/AI_USAGE/components/date-picker.md +1 -1
  18. package/AI_USAGE/components/dialog-api.md +1 -1
  19. package/AI_USAGE/components/dialog.md +1 -1
  20. package/AI_USAGE/components/draggable-api.md +1 -1
  21. package/AI_USAGE/components/draggable.md +1 -1
  22. package/AI_USAGE/components/drawer-api.md +3 -3
  23. package/AI_USAGE/components/drawer.md +1 -1
  24. package/AI_USAGE/components/dropdown-api.md +3 -3
  25. package/AI_USAGE/components/dropdown.md +1 -1
  26. package/AI_USAGE/components/empty-api.md +1 -1
  27. package/AI_USAGE/components/empty.md +1 -1
  28. package/AI_USAGE/components/finicon.md +1 -1
  29. package/AI_USAGE/components/form-api.md +1 -1
  30. package/AI_USAGE/components/form.md +1 -1
  31. package/AI_USAGE/components/grid-api.md +1 -1
  32. package/AI_USAGE/components/grid.md +1 -1
  33. package/AI_USAGE/components/heatmap-api.md +1 -1
  34. package/AI_USAGE/components/heatmap.md +1 -1
  35. package/AI_USAGE/components/icon-api.md +1 -1
  36. package/AI_USAGE/components/icon.md +1 -1
  37. package/AI_USAGE/components/image-api.md +1 -1
  38. package/AI_USAGE/components/image.md +1 -1
  39. package/AI_USAGE/components/input-api.md +2 -2
  40. package/AI_USAGE/components/input-number-api.md +1 -1
  41. package/AI_USAGE/components/input-number.md +1 -1
  42. package/AI_USAGE/components/input-tag-api.md +1 -1
  43. package/AI_USAGE/components/input-tag.md +1 -1
  44. package/AI_USAGE/components/input.md +1 -1
  45. package/AI_USAGE/components/layout-api.md +1 -1
  46. package/AI_USAGE/components/layout.md +1 -1
  47. package/AI_USAGE/components/line-chart-api.md +1 -1
  48. package/AI_USAGE/components/line-chart.md +1 -1
  49. package/AI_USAGE/components/link-api.md +1 -1
  50. package/AI_USAGE/components/link.md +1 -1
  51. package/AI_USAGE/components/menu-api.md +1 -1
  52. package/AI_USAGE/components/menu.md +1 -1
  53. package/AI_USAGE/components/message-api.md +1 -1
  54. package/AI_USAGE/components/message-box-api.md +1 -1
  55. package/AI_USAGE/components/message-box.md +1 -1
  56. package/AI_USAGE/components/message.md +1 -1
  57. package/AI_USAGE/components/network-api.md +1 -1
  58. package/AI_USAGE/components/network.md +1 -1
  59. package/AI_USAGE/components/notification-api.md +1 -1
  60. package/AI_USAGE/components/notification.md +1 -1
  61. package/AI_USAGE/components/pagination-api.md +1 -1
  62. package/AI_USAGE/components/pagination.md +1 -1
  63. package/AI_USAGE/components/pie-chart-api.md +1 -1
  64. package/AI_USAGE/components/pie-chart.md +1 -1
  65. package/AI_USAGE/components/popconfirm-api.md +3 -3
  66. package/AI_USAGE/components/popconfirm.md +1 -1
  67. package/AI_USAGE/components/popover-api.md +1 -1
  68. package/AI_USAGE/components/popover.md +1 -1
  69. package/AI_USAGE/components/popup-api.md +1 -1
  70. package/AI_USAGE/components/popup.md +1 -1
  71. package/AI_USAGE/components/progress-api.md +1 -1
  72. package/AI_USAGE/components/progress.md +1 -1
  73. package/AI_USAGE/components/radio-api.md +1 -1
  74. package/AI_USAGE/components/radio.md +1 -1
  75. package/AI_USAGE/components/rate-api.md +1 -1
  76. package/AI_USAGE/components/rate.md +1 -1
  77. package/AI_USAGE/components/resize-box-api.md +1 -1
  78. package/AI_USAGE/components/resize-box.md +1 -1
  79. package/AI_USAGE/components/scrollbar-api.md +1 -1
  80. package/AI_USAGE/components/scrollbar.md +1 -1
  81. package/AI_USAGE/components/select-api.md +1 -1
  82. package/AI_USAGE/components/select.md +1 -1
  83. package/AI_USAGE/components/skeleton-api.md +1 -1
  84. package/AI_USAGE/components/skeleton.md +1 -1
  85. package/AI_USAGE/components/slider-api.md +1 -1
  86. package/AI_USAGE/components/slider.md +1 -1
  87. package/AI_USAGE/components/space-api.md +1 -1
  88. package/AI_USAGE/components/space.md +1 -1
  89. package/AI_USAGE/components/spin-api.md +1 -1
  90. package/AI_USAGE/components/spin.md +1 -1
  91. package/AI_USAGE/components/steps-api.md +1 -1
  92. package/AI_USAGE/components/steps.md +1 -1
  93. package/AI_USAGE/components/switch-api.md +1 -1
  94. package/AI_USAGE/components/switch.md +1 -1
  95. package/AI_USAGE/components/table-api.md +1 -1
  96. package/AI_USAGE/components/table.md +1 -1
  97. package/AI_USAGE/components/tabs-api.md +1 -1
  98. package/AI_USAGE/components/tabs.md +1 -1
  99. package/AI_USAGE/components/tag-api.md +1 -1
  100. package/AI_USAGE/components/tag.md +1 -1
  101. package/AI_USAGE/components/textarea-api.md +1 -1
  102. package/AI_USAGE/components/textarea.md +1 -1
  103. package/AI_USAGE/components/time-picker-api.md +1 -1
  104. package/AI_USAGE/components/time-picker.md +1 -1
  105. package/AI_USAGE/components/time-range-selector-api.md +1 -1
  106. package/AI_USAGE/components/time-range-selector.md +1 -1
  107. package/AI_USAGE/components/timeline-api.md +3 -3
  108. package/AI_USAGE/components/timeline.md +1 -1
  109. package/AI_USAGE/components/tooltip-api.md +1 -1
  110. package/AI_USAGE/components/tooltip.md +1 -1
  111. package/AI_USAGE/components/transfer-api.md +165 -0
  112. package/AI_USAGE/components/transfer.md +515 -0
  113. package/AI_USAGE/components/tree-select-api.md +1 -1
  114. package/AI_USAGE/components/tree-select.md +1 -1
  115. package/AI_USAGE/components/trend-chart-api.md +1 -1
  116. package/AI_USAGE/components/trend-chart.md +1 -1
  117. package/AI_USAGE/components/trigger-api.md +1 -1
  118. package/AI_USAGE/components/trigger.md +1 -1
  119. package/AI_USAGE/components/upload-api.md +1 -1
  120. package/AI_USAGE/components/upload.md +1 -1
  121. package/AI_USAGE/components/watermark-api.md +1 -1
  122. package/AI_USAGE/components/watermark.md +1 -1
  123. package/AI_USAGE/core.md +1 -1
  124. package/AI_USAGE/index.md +3 -2
  125. package/AI_USAGE/recipes/form-on-demand.md +1 -1
  126. package/AI_USAGE.md +957 -57
  127. package/CHANGELOG.md +40 -0
  128. package/dist/_styles/palette-aliases.d.ts +1 -0
  129. package/dist/components/button/Button.d.ts +0 -9
  130. package/dist/components/button/appearance.d.ts +7 -0
  131. package/dist/components/button/index.d.ts +0 -16
  132. package/dist/components/button/props.d.ts +2 -6
  133. package/dist/components/color-picker/panel.d.ts +0 -9
  134. package/dist/components/date-picker/DatePicker.vue.d.ts +0 -15
  135. package/dist/components/date-picker/index.d.ts +0 -30
  136. package/dist/components/drawer/index.d.ts +0 -30
  137. package/dist/components/drawer/src/Drawer.vue.d.ts +0 -15
  138. package/dist/components/dropdown/DropdownButton.vue.d.ts +0 -15
  139. package/dist/components/dropdown/index.d.ts +0 -30
  140. package/dist/components/index.d.ts +1 -0
  141. package/dist/components/popconfirm/src/popup.vue.d.ts +0 -15
  142. package/dist/components/time-picker/TimePanel.vue.d.ts +0 -15
  143. package/dist/components/time-picker/TimePicker.vue.d.ts +0 -15
  144. package/dist/components/time-picker/index.d.ts +0 -30
  145. package/dist/components/transfer/Transfer.d.ts +211 -0
  146. package/dist/components/transfer/index.d.ts +299 -0
  147. package/dist/components/transfer/interface.d.ts +80 -0
  148. package/dist/components/transfer/transfer-panel.d.ts +82 -0
  149. package/dist/components/transfer/utils.d.ts +5 -0
  150. package/dist/es/_styles/palette-aliases.js +102 -17
  151. package/dist/es/_utils/palette.js +54 -54
  152. package/dist/es/components/button/Button.js +77 -49
  153. package/dist/es/components/button/appearance.js +7 -0
  154. package/dist/es/components/button/props.js +0 -4
  155. package/dist/es/components/index.js +47 -45
  156. package/dist/es/components/transfer/Transfer.js +267 -0
  157. package/dist/es/components/transfer/index.js +7 -0
  158. package/dist/es/components/transfer/transfer-panel.js +251 -0
  159. package/dist/es/components/transfer/utils.js +9 -0
  160. package/dist/es/directives/wave.js +14 -8
  161. package/dist/es/index.js +46 -44
  162. package/dist/es/locale/en-US.js +16 -0
  163. package/dist/es/locale/zh-CN.js +16 -0
  164. package/dist/es/style.css +1 -1
  165. package/dist/index.cjs +3 -3
  166. package/dist/index.umd.js +3 -3
  167. package/dist/locale/interface.d.ts +16 -0
  168. package/dist/style/alert.css +1 -1
  169. package/dist/style/base.css +1 -1
  170. package/dist/style/button.css +1 -1
  171. package/dist/style/color-picker.css +1 -1
  172. package/dist/style/dependencies.json +14 -0
  173. package/dist/style/link.css +1 -1
  174. package/dist/style/transfer.css +1 -0
  175. package/dist/style/transfer.js +12 -0
  176. package/dist/style.css +1 -1
  177. package/dist/types.d.ts +1 -0
  178. package/package.json +3 -1
  179. package/volar.d.ts +1 -0
@@ -0,0 +1,165 @@
1
+ <!-- Generated by pnpm generate:ai-usage. Edit script/ai-usage/content.md and script/ai-usage/. -->
2
+ # Transfer 完整公开 API
3
+
4
+ 适用版本:x-next@1.18.0;来源指纹:`a0432ebab3728998205092a9a7e188702b81ff8c0550430bc02ff73b265af282`。
5
+
6
+ 从同版本构建的公开声明、运行时 props/emits 和显式 expose 生成。运行时导入始终使用 `x-next`,声明路径仅作定位。插槽类型未细化时,具体槽名与作用域见本地用法示例。
7
+
8
+ ## Transfer API
9
+
10
+ 公开声明:`dist/components/transfer/index.d.ts`。 类型中的 undefined 表示可省略;原始 prop 默认值不等于继承配置或服务默认值。
11
+
12
+ ### Props
13
+
14
+ | 名称 | 用途 | 公开类型 | 必填 | 声明默认值 |
15
+ | --- | --- | --- | --- | --- |
16
+ | data | 数据源,value 唯一,支持附加字段 | undefined &#124; TransferItem[] | 否 | [] |
17
+ | modelValue | 见场景用法与类型 | undefined &#124; TransferValue[] | 否 | undefined |
18
+ | defaultValue | 非受控目标初始值 | undefined &#124; TransferValue[] | 否 | [] |
19
+ | selectedKeys | 见场景用法与类型 | undefined &#124; TransferValue[] | 否 | undefined |
20
+ | defaultSelectedKeys | 非受控勾选初始值 | undefined &#124; TransferValue[] | 否 | [] |
21
+ | disabled | 禁用,继承 Form | undefined &#124; false &#124; true | 否 | false |
22
+ | loading | 加载并阻止操作 | undefined &#124; false &#124; true | 否 | false |
23
+ | error | 错误,继承 Form | undefined &#124; false &#124; true | 否 | false |
24
+ | simple | 点击立即移动 | undefined &#124; false &#124; true | 否 | false |
25
+ | oneWay | 单向分配,目标逐项移除 | undefined &#124; false &#124; true | 否 | false |
26
+ | showSearch | 两侧搜索 | undefined &#124; false &#124; true | 否 | false |
27
+ | showSelectAll | 显示全选;simple/oneWay 目标侧不显示 | undefined &#124; false &#124; true | 否 | true |
28
+ | title | 两侧标题,缺项按语言包回退 | undefined &#124; string[] | 否 | 未声明 |
29
+ | operations | 向右、向左操作文案 | undefined &#124; string[] | 否 | [] |
30
+ | searchPlaceholder | 搜索占位 | undefined &#124; string | 否 | 未声明 |
31
+ | filterOption | 非空搜索的过滤函数 | undefined &#124; (input: string, item: TransferItem, type: TransferType) => boolean | 否 | 未声明 |
32
+ | targetOrder | 目标排序 | undefined &#124; "append" &#124; "original" | 否 | "original" |
33
+ | listStyle | 面板样式,可设置 width 或组件 CSS token | undefined &#124; CSSProperties | 否 | 未声明 |
34
+ | pagination | 分页,非法 pageSize 回退 10 | undefined &#124; false &#124; true &#124; TransferPagination | 否 | false |
35
+ | virtualListProps | VirtualList 配置,默认高度 240 | undefined &#124; VirtualListProps | 否 | 未声明 |
36
+
37
+ ### Events
38
+
39
+ | 事件 | 用途 | 监听器签名(即事件参数) |
40
+ | --- | --- | --- |
41
+ | update:modelValue | 请求更新目标模型 | undefined &#124; (_values: TransferValue[]) => any |
42
+ | update:selectedKeys | 请求更新临时勾选模型 | undefined &#124; (_values: TransferValue[]) => any |
43
+ | change | 实际移动,type 为目的侧 | undefined &#124; (_values: TransferValue[], _type: TransferType, _movedValues: TransferValue[]) => any |
44
+ | select | 临时勾选变化或移动清除勾选 | undefined &#124; (_sourceSelected: TransferValue[], _targetSelected: TransferValue[]) => any |
45
+ | search | 输入/清空/隐藏搜索重置 | undefined &#124; (_value: string, _type: TransferType) => any |
46
+ | scroll | 列表滚动 | undefined &#124; (_event: Event, _type: TransferType) => any |
47
+
48
+ ### Slots
49
+
50
+ | 名称 | 用途 | 公开类型 |
51
+ | --- | --- | --- |
52
+ | item | 选项内容 | undefined &#124; (props: TransferItemSlotProps) => VNodeChild |
53
+ | source | 见场景用法与类型 | undefined &#124; (props: TransferListSlotProps) => VNodeChild |
54
+ | target | 见场景用法与类型 | undefined &#124; (props: TransferListSlotProps) => VNodeChild |
55
+ | source-title | 见场景用法与类型 | undefined &#124; (props: TransferTitleSlotProps) => VNodeChild |
56
+ | target-title | 见场景用法与类型 | undefined &#124; (props: TransferTitleSlotProps) => VNodeChild |
57
+ | footer | 两侧页脚 | undefined &#124; (props: TransferListSlotProps) => VNodeChild |
58
+ | empty | 默认列表空态,自定义列表自行处理 | undefined &#124; (props: { type: TransferType; searchValue: string; }) => VNodeChild |
59
+ | to-target-icon | 见场景用法与类型 | undefined &#124; () => VNodeChild |
60
+ | to-source-icon | 见场景用法与类型 | undefined &#124; () => VNodeChild |
61
+ | source / target | 替换对应侧列表 | 文档列出的实际插槽;公开类型未细化,作用域见场景用法 |
62
+ | source-title / target-title | 替换标题 | 文档列出的实际插槽;公开类型未细化,作用域见场景用法 |
63
+ | to-target-icon / to-source-icon | 方向图标 | 文档列出的实际插槽;公开类型未细化,作用域见场景用法 |
64
+
65
+ ### 实例方法
66
+
67
+ 没有检索到显式 expose 或 Options API methods 的公开方法;不把 setup 内部函数当成稳定实例 API。
68
+
69
+ ### 关联类型定义
70
+
71
+ 以下摘自本组件族声明,供查阅嵌套配置;运行时和值类型均以根入口可导出项为准。
72
+
73
+ ```typescript-reference
74
+ type TransferValue = string | number;
75
+
76
+ type TransferType = 'source' | 'target';
77
+
78
+ interface TransferItem {
79
+ value: TransferValue;
80
+ label: string;
81
+ disabled?: boolean;
82
+ [key: string]: unknown;
83
+ }
84
+
85
+ interface TransferPagination {
86
+ /** 每页条数,默认 10 */
87
+ pageSize?: number;
88
+ }
89
+
90
+ interface TransferProps {
91
+ data?: TransferItem[];
92
+ modelValue?: TransferValue[];
93
+ defaultValue?: TransferValue[];
94
+ selectedKeys?: TransferValue[];
95
+ defaultSelectedKeys?: TransferValue[];
96
+ disabled?: boolean;
97
+ loading?: boolean;
98
+ error?: boolean;
99
+ simple?: boolean;
100
+ oneWay?: boolean;
101
+ showSearch?: boolean;
102
+ showSelectAll?: boolean;
103
+ title?: string[];
104
+ operations?: string[];
105
+ searchPlaceholder?: string;
106
+ filterOption?: (inputValue: string, item: TransferItem, type: TransferType) => boolean;
107
+ targetOrder?: 'original' | 'append';
108
+ listStyle?: CSSProperties;
109
+ pagination?: boolean | TransferPagination;
110
+ virtualListProps?: VirtualListProps;
111
+ }
112
+
113
+ interface TransferListSlotProps {
114
+ type: TransferType;
115
+ /** 搜索过滤后的全部数据 */
116
+ data: TransferItem[];
117
+ /** 当前页数据,未分页时等于 data */
118
+ pageData: TransferItem[];
119
+ /** 本侧有效勾选值,包含搜索隐藏项 */
120
+ selectedKeys: TransferValue[];
121
+ disabled: boolean;
122
+ onSelect: (value: TransferValue, checked: boolean) => void;
123
+ onSelectAll: (values: TransferValue[], checked: boolean) => void;
124
+ onMove: (values: TransferValue[]) => void;
125
+ }
126
+
127
+ interface TransferTitleSlotProps {
128
+ type: TransferType;
129
+ title: string;
130
+ countTotal: number;
131
+ countSelected: number;
132
+ searchValue: string;
133
+ checked: boolean;
134
+ indeterminate: boolean;
135
+ disabled: boolean;
136
+ onSelectAllChange: (checked: boolean) => void;
137
+ }
138
+
139
+ interface TransferItemSlotProps {
140
+ item: TransferItem;
141
+ type: TransferType;
142
+ selected: boolean;
143
+ disabled: boolean;
144
+ }
145
+
146
+ interface TransferSlots {
147
+ item?: (props: TransferItemSlotProps) => VNodeChild;
148
+ source?: (props: TransferListSlotProps) => VNodeChild;
149
+ target?: (props: TransferListSlotProps) => VNodeChild;
150
+ 'source-title'?: (props: TransferTitleSlotProps) => VNodeChild;
151
+ 'target-title'?: (props: TransferTitleSlotProps) => VNodeChild;
152
+ footer?: (props: TransferListSlotProps) => VNodeChild;
153
+ empty?: (props: {
154
+ type: TransferType;
155
+ searchValue: string;
156
+ }) => VNodeChild;
157
+ 'to-target-icon'?: () => VNodeChild;
158
+ 'to-source-icon'?: () => VNodeChild;
159
+ }
160
+
161
+ type TransferInstance = InstanceType<typeof Transfer>;
162
+ ```
163
+
164
+
165
+ 返回 [Transfer 用法](./transfer.md)。
@@ -0,0 +1,515 @@
1
+ <!-- Generated by pnpm generate:ai-usage. Edit script/ai-usage/content.md and script/ai-usage/. -->
2
+ # Transfer AI 使用
3
+
4
+ 适用版本:x-next@1.18.0;来源指纹:`a0432ebab3728998205092a9a7e188702b81ff8c0550430bc02ff73b265af282`。
5
+
6
+ 先读 [通用接入](../core.md)。公开导出:`Transfer`;主要模型:v-model、v-model:selected-keys。完整 Props、Events、Slots、实例方法与服务签名见 [本地 API](./transfer-api.md),包含本组件族全部子组件和别名。
7
+
8
+ 按需样式:`x-next/style/transfer`(包含 base.css、button.css、empty.css、form-checkbox.css、form-input.css、form-input-number.css、form-select.css、pagination.css、scrollbar-v2.css、spin.css、trigger.css、transfer.css)。代码块未单独引样式时在应用入口加载全量样式,或按实际所有组件加载 JS 入口;不要仅因复制一个组件页就漏掉其中的 Button 等组合依赖。
9
+
10
+ ## 已核验行为与示例
11
+
12
+ [组件文档与 live demo](https://x-next.yjmf.com/components/transfer)。`data` 是 `{ value: string | number, label: string, disabled?: boolean }[]`,可附加业务字段。`v-model` 是目标侧值数组;`v-model:selected-keys` 是两侧临时勾选数组,彼此独立。`defaultValue` / `defaultSelectedKeys` 只初始化非受控状态。数字与字符串值不同;重复数据值保留首项。目标模型中的未加载值不展示,移动其他项时仍保留。
13
+
14
+ `showSearch=false`、`showSelectAll=true`、`simple=false`、`oneWay=false`、`loading=false`、`disabled=false`。搜索默认不区分大小写,`filterOption(input, item, type)` 适配业务字段。全选只处理当前搜索结果,分页时仅当前页,禁用项不参与;已勾选的搜索隐藏项仍可移动。`simple` 点击即移动;`oneWay` 只显示向右按钮,目标侧逐项移除,禁用项不可移除。加载阻止操作。`targetOrder='original'` 按源数据排序,`append` 按模型顺序。
15
+
16
+ `change(values, type, movedValues)` 的 `type` 是目的侧 `'source' | 'target'`;`select(sourceSelected, targetSelected)` 报告两侧有效勾选;`search(input, type)`、`scroll(event, type)` 报告源/目标侧。受控模型必须回写;不回写时不提交界面状态。Form 只在移动时触发 change,搜索/临时勾选不触发字段校验。
17
+
18
+ `pagination=true | { pageSize }` 默认每页 10,优先于 `virtualListProps`。`item` 自定义内容;`source` / `target` 替换列表,提供 `data`、`pageData`、`selectedKeys`、`disabled`、`onSelect(value, checked)`、`onSelectAll(values, checked)`、`onMove(values)`。回调统一校验同侧、存在性、禁用和加载。自定义列表自行实现空态、虚拟滚动及键盘语义;默认列表用 Tab/Space 和方向键/Home/End 操作。没有 readonly、远程分页、拖拽排序或字段映射 API。
19
+
20
+ ```vue
21
+ <script setup lang="ts">
22
+ import { ref } from 'vue';
23
+ import { Transfer } from 'x-next';
24
+ import type { TransferItem, TransferValue, TransferType } from 'x-next';
25
+ import 'x-next/style/transfer';
26
+ const values = ref<TransferValue[]>(['audit']);
27
+ const data: TransferItem[] = [
28
+ { value: 'read', label: '查看数据' },
29
+ { value: 'edit', label: '编辑数据' },
30
+ { value: 'audit', label: '审核数据' },
31
+ { value: 'admin', label: '管理配置', disabled: true },
32
+ ];
33
+ const log = ref('');
34
+ function changed(next: TransferValue[], type: TransferType, moved: TransferValue[]) {
35
+ log.value = `${type} ${moved.join(',')};目标值 ${JSON.stringify(next)}`;
36
+ }
37
+ </script>
38
+ <template>
39
+ <Transfer v-model="values" :data="data" show-search @change="changed" />
40
+ <p aria-live="polite">{{ log }}</p>
41
+ </template>
42
+ ```
43
+
44
+ ## 场景用法
45
+
46
+ 以下示例从本地 `src/docs/components/transfer.md` 显式导入到独立 AI 源,补齐局部注册、状态和样式后进行严格模板检查。上方已核验行为优先;原始 prop 默认值、包装透传和示例业务适配分别查 [完整 API](./transfer-api.md) 与场景说明。类型通过不代表所有散文和交互已验证。
47
+
48
+ ### 用途与选型
49
+
50
+ 在两列列表之间移动数据,用于权限分配、成员分组和资源授权。
51
+
52
+
53
+ ### 何时使用
54
+
55
+ - 同时查看候选与已分配数据,进行批量分配或取消分配。
56
+ - 选项包含较多业务信息,Select 展开空间不足。
57
+ - 自定义列表可以接入表格或树;层级关联与列表键盘逻辑由业务组合实现。
58
+
59
+
60
+ ### 基础用法与移动事件
61
+
62
+ 先勾选,再点击方向按钮。`change` 的第二参数是移动目的侧,第三参数仅包含实际移动值。
63
+
64
+ ```vue
65
+ <script setup lang="ts">
66
+ import 'x-next/style.css';
67
+ import { reactive, ref } from 'vue';
68
+ import { Transfer } from 'x-next';
69
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
70
+ const basicValue = ref<TransferValue[]>(['audit']);
71
+ const basicData: TransferItem[] = [
72
+ { value: 'read', label: '查看数据' },
73
+ { value: 'edit', label: '编辑数据' },
74
+ { value: 'audit', label: '审核数据' },
75
+ { value: 'admin', label: '管理配置(不可分配)', disabled: true },
76
+ ];
77
+ const basicLog = ref('请勾选权限并移动');
78
+ function basicChange(value: TransferValue[], type: TransferType, moved: TransferValue[]) {
79
+ basicLog.value = `移至 ${type}:${moved.join(', ')};当前值 ${JSON.stringify(value)}`;
80
+ }
81
+ </script>
82
+ <template>
83
+ <Transfer
84
+ v-model="basicValue"
85
+ :data="basicData"
86
+ :title="['可分配权限', '已分配权限']"
87
+ @change="basicChange"
88
+ />
89
+ <p aria-live="polite">{{ basicLog }}</p>
90
+ <p>目标值:{{ basicValue }}</p>
91
+ </template>
92
+ ```
93
+
94
+ ### 受控勾选与目标排序
95
+
96
+ `v-model:selected-keys` 控制两侧临时勾选,与目标值独立。`target-order="append"` 以模型顺序展示目标项。
97
+
98
+ ```vue
99
+ <script setup lang="ts">
100
+ import 'x-next/style.css';
101
+ import { reactive, ref } from 'vue';
102
+ import { Transfer, Button } from 'x-next';
103
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
104
+ const checkedValue = ref<TransferValue[]>([2]);
105
+ const checkedKeys = ref<TransferValue[]>([1]);
106
+ const checkedData: TransferItem[] = Array.from({ length: 6 }, (_, index) => ({
107
+ value: index + 1,
108
+ label: `成员 ${index + 1}`,
109
+ }));
110
+ const checkedLog = ref('');
111
+ function checkedSelect(source: TransferValue[], target: TransferValue[]) {
112
+ checkedLog.value = `左侧 ${JSON.stringify(source)};右侧 ${JSON.stringify(target)}`;
113
+ }
114
+ </script>
115
+ <template>
116
+ <p
117
+ ><Button @click="checkedKeys = [1, 2, 3]">勾选成员 1 / 2 / 3</Button>
118
+ <Button @click="checkedKeys = []">取消所有勾选</Button></p
119
+ >
120
+ <Transfer
121
+ v-model="checkedValue"
122
+ v-model:selected-keys="checkedKeys"
123
+ :data="checkedData"
124
+ target-order="append"
125
+ @select="checkedSelect"
126
+ />
127
+ <p>目标:{{ checkedValue }};勾选:{{ checkedKeys }}</p>
128
+ <p aria-live="polite">{{ checkedLog }}</p>
129
+ </template>
130
+ ```
131
+
132
+ ### 搜索与过滤后的全选
133
+
134
+ 全选只作用于当前搜索结果,禁用项不参与;已勾选的隐藏项仍可以移动。自定义过滤可搜索附加业务字段。
135
+
136
+ ```vue
137
+ <script setup lang="ts">
138
+ import 'x-next/style.css';
139
+ import { reactive, ref } from 'vue';
140
+ import { Transfer } from 'x-next';
141
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
142
+ const searchValue = ref<TransferValue[]>([]);
143
+ const searchData: TransferItem[] = [
144
+ { value: 'east-1', label: '杭州', region: '华东' },
145
+ { value: 'east-2', label: '上海', region: '华东' },
146
+ { value: 'north', label: '北京', region: '华北' },
147
+ { value: 'south', label: '深圳', region: '华南', disabled: true },
148
+ ];
149
+ const searchLog = ref('尝试搜索“华东”,然后全选');
150
+ function searchFilter(input: string, item: TransferItem) {
151
+ return `${item.label} ${String(item.region ?? '')}`.includes(input.trim());
152
+ }
153
+ function searchChanged(input: string, type: TransferType) {
154
+ searchLog.value = `${type} 搜索:${input || '已清空'}`;
155
+ }
156
+ </script>
157
+ <template>
158
+ <Transfer
159
+ v-model="searchValue"
160
+ :data="searchData"
161
+ show-search
162
+ search-placeholder="搜索城市或大区"
163
+ :filter-option="searchFilter"
164
+ @search="searchChanged"
165
+ />
166
+ <p aria-live="polite">{{ searchLog }}</p>
167
+ <p>目标值:{{ searchValue }}</p>
168
+ </template>
169
+ ```
170
+
171
+ ### 禁用、加载与错误状态
172
+
173
+ 加载时显示真实加载组件并阻止操作。单项禁用只影响该项;`error` 同时支持从 Form 继承。
174
+
175
+ ```vue
176
+ <script setup lang="ts">
177
+ import 'x-next/style.css';
178
+ import { reactive, ref } from 'vue';
179
+ import { Transfer, Checkbox } from 'x-next';
180
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
181
+ const stateValue = ref<TransferValue[]>([1]);
182
+ const stateDisabled = ref(false);
183
+ const stateLoading = ref(false);
184
+ const stateError = ref(false);
185
+ const stateData: TransferItem[] = [
186
+ { value: 1, label: '业务成员' },
187
+ { value: 2, label: '运维成员' },
188
+ { value: 3, label: '只读成员(禁用)', disabled: true },
189
+ { value: 4, label: '这是一个用于检查溢出省略和原生标题的超长成员名称' },
190
+ ];
191
+ </script>
192
+ <template>
193
+ <p
194
+ ><Checkbox v-model="stateDisabled">禁用</Checkbox>
195
+ <Checkbox v-model="stateLoading">加载中</Checkbox>
196
+ <Checkbox v-model="stateError">错误</Checkbox></p
197
+ >
198
+ <Transfer
199
+ v-model="stateValue"
200
+ :data="stateData"
201
+ :disabled="stateDisabled"
202
+ :loading="stateLoading"
203
+ :error="stateError"
204
+ show-search
205
+ />
206
+ </template>
207
+ ```
208
+
209
+ ### 单向分配与逐项移除
210
+
211
+ 只保留向右按钮,目标侧使用可通过键盘到达的移除按钮。已分配的禁用项不能移除。
212
+
213
+ ```vue
214
+ <script setup lang="ts">
215
+ import 'x-next/style.css';
216
+ import { reactive, ref } from 'vue';
217
+ import { Transfer } from 'x-next';
218
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
219
+ const oneWayValue = ref<TransferValue[]>(['owner', 'viewer']);
220
+ const oneWayData: TransferItem[] = [
221
+ { value: 'owner', label: '固定负责人', disabled: true },
222
+ { value: 'viewer', label: '查看成员' },
223
+ { value: 'editor', label: '编辑成员' },
224
+ ];
225
+ </script>
226
+ <template>
227
+ <Transfer v-model="oneWayValue" :data="oneWayData" one-way :operations="['分配']" />
228
+ <p>已分配:{{ oneWayValue }}</p>
229
+ </template>
230
+ ```
231
+
232
+ ### 简单模式
233
+
234
+ 点击选项直接移动,也支持 Tab 与 Enter/Space。与 `one-way` 组合时,目标侧仍使用移除按钮。
235
+
236
+ ```vue
237
+ <script setup lang="ts">
238
+ import 'x-next/style.css';
239
+ import { reactive, ref } from 'vue';
240
+ import { Transfer } from 'x-next';
241
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
242
+ const simpleValue = ref<TransferValue[]>(['b']);
243
+ const simpleData: TransferItem[] = [
244
+ { value: 'a', label: '开发组' },
245
+ { value: 'b', label: '产品组' },
246
+ { value: 'c', label: '测试组' },
247
+ { value: 'd', label: '归档组', disabled: true },
248
+ ];
249
+ </script>
250
+ <template>
251
+ <Transfer v-model="simpleValue" :data="simpleData" simple />
252
+ <p>点击组名即可移动:{{ simpleValue }}</p>
253
+ </template>
254
+ ```
255
+
256
+ ### 自定义选项、标题、图标和页脚
257
+
258
+ item 仅替换内容,保留原生勾选交互。标题通过 `onSelectAllChange` 调用当前搜索结果/页内的全选。
259
+
260
+ ```vue
261
+ <script setup lang="ts">
262
+ import 'x-next/style.css';
263
+ import { reactive, ref } from 'vue';
264
+ import { Transfer, Checkbox } from 'x-next';
265
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
266
+ const slotValue = ref<TransferValue[]>([]);
267
+ const slotData: TransferItem[] = [
268
+ { value: 1, label: '林老师', role: '产品设计' },
269
+ { value: 2, label: '陈同学', role: '前端研发' },
270
+ { value: 3, label: '张同学', role: '质量保障' },
271
+ ];
272
+ </script>
273
+ <template>
274
+ <Transfer
275
+ v-model="slotValue"
276
+ :data="slotData"
277
+ show-search
278
+ :title="['团队成员', '项目成员']"
279
+ :list-style="{ width: '260px' }"
280
+ >
281
+ <template #item="{ item }"
282
+ ><span>{{ item.label }} · {{ item.role }}</span></template
283
+ >
284
+ <template #source-title="{ title, checked, indeterminate, disabled, onSelectAllChange }">
285
+ <Checkbox
286
+ :model-value="checked"
287
+ :indeterminate="indeterminate"
288
+ :disabled="disabled"
289
+ @change="onSelectAllChange($event === true)"
290
+ >{{ title }}</Checkbox
291
+ >
292
+ </template>
293
+ <template #to-target-icon><span aria-hidden="true">→</span></template>
294
+ <template #to-source-icon><span aria-hidden="true">←</span></template>
295
+ <template #footer="{ type, data, selectedKeys }"
296
+ ><small
297
+ >{{ type === 'source' ? '可选' : '已选' }} {{ data.length }} 人,勾选
298
+ {{ selectedKeys.length }} 人</small
299
+ ></template
300
+ >
301
+ </Transfer>
302
+ </template>
303
+ ```
304
+
305
+ ### 自定义列表
306
+
307
+ source/target 替换列表内容。回调接入表格、树或业务卡片,保持共享移动规则。示例按钮支持键盘,并用 aria-pressed 表达勾选状态。
308
+
309
+ ```vue
310
+ <script setup lang="ts">
311
+ import 'x-next/style.css';
312
+ import { reactive, ref } from 'vue';
313
+ import { Transfer } from 'x-next';
314
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
315
+ const customValue = ref<TransferValue[]>(['release']);
316
+ const customData: TransferItem[] = [
317
+ { value: 'design', label: '设计评审' },
318
+ { value: 'develop', label: '研发联调' },
319
+ { value: 'release', label: '上线验证' },
320
+ { value: 'archived', label: '已归档', disabled: true },
321
+ ];
322
+ </script>
323
+ <template>
324
+ <Transfer v-model="customValue" :data="customData" show-search>
325
+ <template #source="{ pageData, selectedKeys, disabled, onSelect }">
326
+ <div style="padding: 12px; display: grid; gap: 8px">
327
+ <button
328
+ v-for="item in pageData"
329
+ :key="item.value"
330
+ type="button"
331
+ :disabled="disabled || item.disabled"
332
+ :aria-pressed="selectedKeys.includes(item.value)"
333
+ @click="onSelect(item.value, !selectedKeys.includes(item.value))"
334
+ >
335
+ {{ selectedKeys.includes(item.value) ? '✓ ' : '+ ' }}{{ item.label }}
336
+ </button>
337
+ <span v-if="!pageData.length">没有可选任务</span>
338
+ </div>
339
+ </template>
340
+ <template #target="{ pageData, selectedKeys, disabled, onSelect }">
341
+ <div style="padding: 12px; display: grid; gap: 8px">
342
+ <button
343
+ v-for="item in pageData"
344
+ :key="item.value"
345
+ type="button"
346
+ :disabled="disabled || item.disabled"
347
+ :aria-pressed="selectedKeys.includes(item.value)"
348
+ @click="onSelect(item.value, !selectedKeys.includes(item.value))"
349
+ >
350
+ {{ selectedKeys.includes(item.value) ? '✓ ' : '+ ' }}{{ item.label }}
351
+ </button>
352
+ <span v-if="!pageData.length">尚未分配任务</span>
353
+ </div>
354
+ </template>
355
+ </Transfer>
356
+ <p>当前项目任务:{{ customValue }}</p>
357
+ </template>
358
+ ```
359
+
360
+ ### 分页
361
+
362
+ 两侧页码独立,全选仅当前页。搜索或每页条数变化后回到第一页,移动使页码超出范围时自动收敛。
363
+
364
+ ```vue
365
+ <script setup lang="ts">
366
+ import 'x-next/style.css';
367
+ import { reactive, ref } from 'vue';
368
+ import { Transfer } from 'x-next';
369
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
370
+ const pagedValue = ref<TransferValue[]>([2, 4]);
371
+ const pagedData: TransferItem[] = Array.from({ length: 30 }, (_, index) => ({
372
+ value: index + 1,
373
+ label: `候选成员 ${index + 1}`,
374
+ disabled: index === 8,
375
+ }));
376
+ </script>
377
+ <template>
378
+ <Transfer v-model="pagedValue" :data="pagedData" :pagination="{ pageSize: 5 }" show-search />
379
+ <p>已分配:{{ pagedValue }}</p>
380
+ </template>
381
+ ```
382
+
383
+ ### 虚拟滚动
384
+
385
+ 大数据列表复用库内 VirtualList。分页优先于虚拟滚动;自定义列表自行决定渲染方式。
386
+
387
+ ```vue
388
+ <script setup lang="ts">
389
+ import 'x-next/style.css';
390
+ import { reactive, ref } from 'vue';
391
+ import { Transfer } from 'x-next';
392
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
393
+ const virtualValue = ref<TransferValue[]>([100, 500]);
394
+ const virtualData: TransferItem[] = Array.from({ length: 1000 }, (_, index) => ({
395
+ value: index + 1,
396
+ label: `数据项 ${index + 1}`,
397
+ }));
398
+ const virtualLog = ref('尝试滚动列表或搜索数据项 999');
399
+ function virtualScroll(_event: Event, type: TransferType) {
400
+ virtualLog.value = `${type} 列表正在滚动`;
401
+ }
402
+ </script>
403
+ <template>
404
+ <Transfer
405
+ v-model="virtualValue"
406
+ :data="virtualData"
407
+ show-search
408
+ :virtual-list-props="{
409
+ height: 240,
410
+ threshold: 30,
411
+ fixedSize: true,
412
+ estimatedSize: 36,
413
+ buffer: 5,
414
+ }"
415
+ @scroll="virtualScroll"
416
+ />
417
+ <p aria-live="polite">{{ virtualLog }}</p>
418
+ <p>目标值:{{ virtualValue }}</p>
419
+ </template>
420
+ ```
421
+
422
+ ### Form 校验联动
423
+
424
+ 勾选和搜索不改变字段值;实际移动才触发 change 校验。标签/必填/错误说明绑定到整个组,内部控件不会重复注册。
425
+
426
+ ```vue
427
+ <script setup lang="ts">
428
+ import 'x-next/style.css';
429
+ import { reactive, ref } from 'vue';
430
+ import { Transfer, Button, FormItem, Form } from 'x-next';
431
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
432
+ const transferFormRef = ref<FormInstance>();
433
+ const transferForm = reactive({ members: [] as TransferValue[] });
434
+ const transferRules: Record<string, FieldRule[]> = {
435
+ members: [{ type: 'array', required: true, minLength: 2, message: '请至少分配 2 个成员' }],
436
+ };
437
+ const transferFormData: TransferItem[] = [
438
+ { value: 'lin', label: '林老师' },
439
+ { value: 'chen', label: '陈同学' },
440
+ { value: 'zhang', label: '张同学' },
441
+ ];
442
+ const transferFormLog = ref('');
443
+ async function validateTransfer() {
444
+ transferFormLog.value = (await transferFormRef.value?.validate()) ? '请补齐成员' : '校验通过';
445
+ }
446
+ </script>
447
+ <template>
448
+ <Form ref="transferFormRef" :model="transferForm" :rules="transferRules" layout="vertical">
449
+ <FormItem field="members" label="项目成员" required>
450
+ <Transfer v-model="transferForm.members" :data="transferFormData" show-search />
451
+ </FormItem>
452
+ <Button type="primary" @click="validateTransfer">校验成员</Button>
453
+ <Button @click="transferFormRef?.resetFields()">重置</Button>
454
+ <p aria-live="polite">{{ transferFormLog }}</p>
455
+ </Form>
456
+ </template>
457
+ ```
458
+
459
+ ### 空态与异步数据
460
+
461
+ 模型中暂时没有对应数据的值会保留,数据到达后展示。空态插槽能区分源侧、目标侧和搜索条件。
462
+
463
+ ```vue
464
+ <script setup lang="ts">
465
+ import 'x-next/style.css';
466
+ const searchValue = ref<TransferValue[]>([]);
467
+
468
+ import { reactive, ref } from 'vue';
469
+ import { Transfer, Button } from 'x-next';
470
+ import type { TransferItem, TransferValue, TransferType, FormInstance, FieldRule } from 'x-next';
471
+ const emptyValue = ref<TransferValue[]>(['remote']);
472
+ const emptyData = ref<TransferItem[]>([]);
473
+ function loadTransferData() {
474
+ emptyData.value = [
475
+ { value: 'remote', label: '已分配的远程成员' },
476
+ { value: 'new', label: '新加载的候选成员' },
477
+ ];
478
+ }
479
+ </script>
480
+ <template>
481
+ <p
482
+ ><Button @click="loadTransferData">加载模拟数据</Button>
483
+ <Button @click="emptyData = []">清空数据源</Button></p
484
+ >
485
+ <Transfer v-model="emptyValue" :data="emptyData" show-search>
486
+ <template #empty="{ type, searchValue }"
487
+ ><span>{{
488
+ searchValue ? '没有匹配的成员' : type === 'source' ? '暂无候选成员' : '暂无已加载成员'
489
+ }}</span></template
490
+ >
491
+ </Transfer>
492
+ <p>模型值保留:{{ emptyValue }}</p>
493
+ </template>
494
+ ```
495
+
496
+ ### 键盘与行为边界
497
+
498
+ - Tab 到达搜索、全选、选项和方向按钮;Space 勾选复选框,Enter/Space 激活方向/移除/简单模式按钮。
499
+ - 默认列表支持 ↑ / ↓、Home / End 定位,跳过禁用项。自定义列表由业务实现键盘语义。
500
+ - 勾选值与目标值分别受控;传入模型而不回写时保持原值。默认值只在创建时初始化。
501
+ - `value` 必须全局唯一,数字 `1` 和字符串 `"1"` 不同。重复项保留首项,非法值不展示;不原地修改输入数组。
502
+ - 默认搜索不区分大小写。全选仅当前搜索结果,分页时仅当前页;已勾选的搜索隐藏项仍参与移动。
503
+ - 禁用项不能全选、移入或移除。缺失数据的目标值在移动其他项时保留。
504
+ - `targetOrder="original"` 按数据源排序;`append` 按模型顺序,移入值追加在已有目标值之后。
505
+ - `pagination` 优先于 `virtualListProps`。source/target 插槽接收过滤数据和当前页数据,自行实现虚拟渲染与键盘。
506
+ - 数组控件没有 readonly 属性;只读展示可使用 disabled。字段映射、远程分页、拖拽排序需业务适配。
507
+
508
+
509
+ ### 数据类型
510
+
511
+ 组合参见 [Form 表单](./form.md)、[Checkbox 复选框](./checkbox.md)、[Table 表格](./table.md)、[TreeSelect 树选择器](./tree-select.md)。
512
+
513
+
514
+
515
+ 返回 [AI 索引](../index.md)。先查本页与 [本地 API](./transfer-api.md);需要更深类型时查 [公开组件导航](../catalog.md),不默认上网查找本包用法。