跳转到内容

FieldArray 字段数组 ​

用于管理可添加、删除和排序的重复字段。

用法 ​

添加和删除重复字段

组件结构 ​

加粗的是必需部件。

data-scope="field-array":root · item · item-label · item-content · item-action · add-trigger · item-delete-trigger · move-up-trigger · move-down-trigger

示例 ​

数量限制 ​

设置最少和最多行数

排序 ​

上移或下移字段

1.
2.
3.
4.

多字段行 ​

每行包含多个输入框

设计指引 ​

何时使用 ​

  • 联系方式、规格参数、收件人等数量可变的字段。

何时不用 ​

  • 行数固定时直接使用普通字段。
  • 每项只是短文本时使用标签输入。

特性 ​

  • min 与 max 限制行数。
  • movable 启用上移和下移操作。
  • createItem 设置新增行的初始值。
  • 每行可以包含一个或多个字段。
  • 在 Form 中会同步迁移数组子字段的值、规则和错误。

组合 ​

  • 每一行放表单字段,行内多个字段用行布局排列;整组挂在表单下由它迁移值、规则与错误。
  • 行序也可以交给排序拖拽调整;movable 只提供上移、下移两个按钮。

最佳实践 ​

  • 新增后将焦点移到新行的第一个输入框。
  • 删除按钮应说明目标行。
  • 到达数量限制时保持操作按钮可见并禁用。

反模式 ​

  • 删除后无法撤销。
  • 只在提交时提示数量限制。

API 参考 ​

产物 ​

层值
自定义元素<xh-field-array>
Vue 组件XhFieldArrayAddTrigger XhFieldArrayItem XhFieldArrayItemAction XhFieldArrayItemContent XhFieldArrayItemDeleteTrigger XhFieldArrayItemLabel XhFieldArrayMoveDownTrigger XhFieldArrayMoveUpTrigger XhFieldArrayRoot
组合式函数useFieldArray
状态机fieldArrayMachine
皮肤@xihan-ui/styles/field-array.css

Props ​

属性类型必填说明
valueunknown[]受控数据数组;提供后由宿主决定,状态机不自行修改,只发 onValueChange。
defaultValueunknown[]非受控初始数据数组。
minnumber最少行数。到达该数值时删除把手不可按下。默认 0。
maxnumber最多行数。到达该数值时新增把手不可按下。默认不限。
createItem() => unknown新增一行时创建一个空项。未提供时插入 null。
movableboolean是否显示换序把手。关闭(默认)时两个换序把手一律收起。
disabledboolean禁用:新增、删除、换序三路都不可按下。
readOnlyboolean只读:行数不可修改(新增、删除、换序都不可按下),行内的控件仍由作者自行设置只读。
invalidboolean校验失败标注:写在根与每一行上。
nameFormPath整份数组的表单字段名。嵌套在 Form 中时会自动接入其值、规则、错误与校验真源; 每一行经 item.name 获得显式数组 FormPath,不拼接字符串下标。
translationsPartial<FieldArrayTranslations>
onValueChange(details: FieldArrayValueChangeDetails) => void

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeFieldArrayValueChangeDetails数据数组变化;detail 为 { value: unknown[] }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhFieldArrayRootdefaultFieldArrayRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhFieldArrayItemindexnumber | string是下标由作者声明;兼收字符串,与另外两个适配器的属性口径对齐。
XhFieldArrayRootchildrenSlotChildren<FieldArrayRootSlotProps>

状态 ​

以下名称仅用于内部状态机。

状态:idle

事件:VALUE.SET · ITEM.ADD · ITEM.REMOVE · ITEM.MOVE · FORM.RESET · PRESS.START · PRESS.END

判据:canAdd · canRemove · canMove · canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valueunknown[]
itemsFieldArrayItem[]逐行的读侧投影,含渲染用的 key。
countnumber
emptyboolean
disabledboolean
readOnlyboolean
invalidboolean
movableboolean
atMinboolean已到下限:再删除会少于 min。
atMaxboolean已到上限:再新增会多于 max。
canAddboolean
setValue(next: unknown[]) => void整份替换,不受 min / max 约束。
add() => void
remove(index: number) => void
move(from: number, to: number) => void
moveUp(index: number) => void
moveDown(index: number) => void
getRootProps() => T['element']
getItemProps(item: FieldArrayItemProps) => T['element']
getItemLabelProps(item: FieldArrayItemProps) => T['element']行前的行号或名目:纯标注,不与行内的控件建立 for 关联。
getItemContentProps(item: FieldArrayItemProps) => T['element']
getItemActionProps(item: FieldArrayItemProps) => T['element']
getAddTriggerProps() => T['button']
getItemDeleteTriggerProps(item: FieldArrayItemProps) => T['button']
getMoveUpTriggerProps(item: FieldArrayItemProps) => T['button']
getMoveDownTriggerProps(item: FieldArrayItemProps) => T['button']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enter / Spaceheld on add-trigger / item-delete-trigger / move-up-trigger / move-down-trigger, not aria-disabled按住期间该把手投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,删除 / 换序落地后把手随行离场或换位时一并撤下

ARIA ​

以下属性由 connect 生成。

部件属性值
add-triggeraria-disabled'false' | 'true'
item-delete-triggeraria-disabled'false' | 'true'
item-delete-triggeraria-labellabel.deleteItem(item.index + 1, count)

样式参考 ​

皮肤 ​

@xihan-ui/styles/field-array.css 使用 [data-scope="field-array"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-at-max''(条件成立时才出现)
rootdata-at-min''(条件成立时才出现)
rootdata-disabled''(条件成立时才出现)
rootdata-empty''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-movable''(条件成立时才出现)
rootdata-readonly''(条件成立时才出现)
itemdata-at-max''(条件成立时才出现)
itemdata-at-min''(条件成立时才出现)
itemdata-disabled''(条件成立时才出现)
itemdata-first''(条件成立时才出现)
itemdata-indexString(item.index)
itemdata-invalid''(条件成立时才出现)
itemdata-last''(条件成立时才出现)
itemdata-readonly''(条件成立时才出现)
item-labeldata-at-max''(条件成立时才出现)
item-labeldata-at-min''(条件成立时才出现)
item-labeldata-disabled''(条件成立时才出现)
item-labeldata-indexString(item.index)
item-labeldata-invalid''(条件成立时才出现)
item-labeldata-readonly''(条件成立时才出现)
item-contentdata-at-max''(条件成立时才出现)
item-contentdata-at-min''(条件成立时才出现)
item-contentdata-disabled''(条件成立时才出现)
item-contentdata-indexString(item.index)
item-contentdata-invalid''(条件成立时才出现)
item-contentdata-readonly''(条件成立时才出现)
item-actiondata-at-max''(条件成立时才出现)
item-actiondata-at-min''(条件成立时才出现)
item-actiondata-disabled''(条件成立时才出现)
item-actiondata-indexString(item.index)
item-actiondata-invalid''(条件成立时才出现)
item-actiondata-readonly''(条件成立时才出现)
add-triggerdata-disabled''(条件成立时才出现)
add-triggerdata-pressed''(条件成立时才出现)
add-triggerdata-xh-action-control''
add-triggerdata-xh-action-display'always'
add-triggerdata-xh-action-profile'text'
add-triggerdata-xh-action-size'md'
add-triggerdata-xh-action-variant'outline'
item-delete-triggerdata-at-max''(条件成立时才出现)
item-delete-triggerdata-at-min''(条件成立时才出现)
item-delete-triggerdata-disabled''(条件成立时才出现)
item-delete-triggerdata-indexString(item.index)
item-delete-triggerdata-invalid''(条件成立时才出现)
item-delete-triggerdata-pressed''(条件成立时才出现)
item-delete-triggerdata-readonly''(条件成立时才出现)
item-delete-triggerdata-xh-action-control''
item-delete-triggerdata-xh-action-display'always'
item-delete-triggerdata-xh-action-profile'icon'
item-delete-triggerdata-xh-action-size'xs'
item-delete-triggerdata-xh-action-variant'ghost'
move-up-triggerdata-pressed''(条件成立时才出现)
move-up-triggerdata-xh-action-control''
move-up-triggerdata-xh-action-display'always'
move-up-triggerdata-xh-action-profile'icon'
move-up-triggerdata-xh-action-size'xs'
move-up-triggerdata-xh-action-variant'ghost'
move-down-triggerdata-pressed''(条件成立时才出现)
move-down-triggerdata-xh-action-control''
move-down-triggerdata-xh-action-display'always'
move-down-triggerdata-xh-action-profile'icon'
move-down-triggerdata-xh-action-size'xs'
move-down-triggerdata-xh-action-variant'ghost'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-field-array-action-gapadd-trigger
item-action
gapdefault--xh-space-1field-array 的 add-trigger、item-action 部件 gap 覆盖槽。
--xh-field-array-add-bgadd-triggerbackground-colordefault--xh-_action-variant-bg-restfield-array 的 add-trigger 部件 background-color 覆盖槽。
--xh-field-array-add-bg-activeadd-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedfield-array 的 add-trigger 部件 background-color 覆盖槽。
--xh-field-array-add-bg-hoveradd-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverfield-array 的 add-trigger 部件 background-color 覆盖槽。
--xh-field-array-add-borderadd-triggerborderdefault--xh-_action-variant-border-restfield-array 的 add-trigger 部件 border 覆盖槽。
--xh-field-array-add-border-disabledadd-triggerborder-colordisabled--xh-_action-variant-border-disabledfield-array 的 add-trigger 部件 border-color 覆盖槽。
--xh-field-array-add-border-hoveradd-triggerborder-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-border-hoverfield-array 的 add-trigger 部件 border-color 覆盖槽。
--xh-field-array-add-fgadd-triggercolordefault
disabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-brandfield-array 的 add-trigger 部件 color 覆盖槽。
--xh-field-array-add-font-sizeadd-triggerfont-sizedefault--xh-text-label-sizefield-array 的 add-trigger 部件 font-size 覆盖槽。
--xh-field-array-add-heightadd-triggerblock-size
inline-size
default
xh-action-profile=icon
--xh-_action-profile-visual-sizefield-array 的 add-trigger 部件 block-size、inline-size 覆盖槽。
--xh-field-array-add-pxadd-triggerpadding-inlinedefault--xh-_action-profile-padding-inlinefield-array 的 add-trigger 部件 padding-inline 覆盖槽。
--xh-field-array-add-radiusadd-triggerborder-radiusdefault--xh-shape-controlfield-array 的 add-trigger 部件 border-radius 覆盖槽。
--xh-field-array-content-gapitem-contentgapdefault--xh-space-2field-array 的 item-content 部件 gap 覆盖槽。
--xh-field-array-gaprootgapdefault--xh-space-2field-array 的 root 部件 gap 覆盖槽。
--xh-field-array-icon-sizeadd-trigger
item-delete-trigger
move-down-trigger
move-up-trigger
--xh-icon-sizedefault--xh-_action-profile-glyph-sizefield-array 的 add-trigger、item-delete-trigger、move-down-trigger、move-up-trigger 部件 --xh-icon-size 覆盖槽。
--xh-field-array-item-delete-fg-hoveritem-delete-triggercolordisabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-danger-hoverfield-array 的 item-delete-trigger 部件 color 覆盖槽。
--xh-field-array-item-gapitemgapdefault--xh-space-2field-array 的 item 部件 gap 覆盖槽。
--xh-field-array-item-label-fgitem-labelcolordefault--xh-fg-mutedfield-array 的 item-label 部件 color 覆盖槽。
--xh-field-array-item-label-font-sizeitem-labelfont-sizedefault--xh-text-secondary-sizefield-array 的 item-label 部件 font-size 覆盖槽。
--xh-field-array-item-paddingitempaddingdefault--xh-space-0field-array 的 item 部件 padding 覆盖槽。
--xh-field-array-item-radiusitemborder-radiusdefault--xh-shape-surfacefield-array 的 item 部件 border-radius 覆盖槽。
--xh-field-array-trigger-bgitem-delete-trigger
move-down-trigger
move-up-trigger
background-colordefault--xh-_action-variant-bg-restfield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 background-color 覆盖槽。
--xh-field-array-trigger-bg-activeitem-delete-trigger
move-down-trigger
move-up-trigger
background-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedfield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 background-color 覆盖槽。
--xh-field-array-trigger-bg-hoveritem-delete-trigger
move-down-trigger
move-up-trigger
background-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverfield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 background-color 覆盖槽。
--xh-field-array-trigger-fgitem-delete-trigger
move-down-trigger
move-up-trigger
colordefault--xh-fg-mutedfield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 color 覆盖槽。
--xh-field-array-trigger-fg-hoveritem-delete-trigger
move-down-trigger
move-up-trigger
colordisabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-defaultfield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 color 覆盖槽。
--xh-field-array-trigger-font-sizeitem-delete-trigger
move-down-trigger
move-up-trigger
font-sizedefault--xh-text-secondary-sizefield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 font-size 覆盖槽。
--xh-field-array-trigger-radiusitem-delete-trigger
move-down-trigger
move-up-trigger
border-radiusdefault--xh-shape-controlfield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 border-radius 覆盖槽。
--xh-field-array-trigger-sizeitem-delete-trigger
move-down-trigger
move-up-trigger
block-size
inline-size
min-inline-size
default
xh-action-profile=icon
--xh-_action-profile-visual-sizefield-array 的 item-delete-trigger、move-down-trigger、move-up-trigger 部件 block-size、inline-size、min-inline-size 覆盖槽。

动效 ​

本组件皮肤不含过渡与关键帧,也没有脚本驱动的动效:状态一变,外观立即到位。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。

Released under The MIT License