Skip to content

useFieldArray ​

字段列表:订单项、电话、参与者。为 v-for 提供稳定的键以及行操作。删除或重新排序行时,“已访问”标记会随行移动 —— 错误不会跳到相邻的行。

签名 ​

ts
function useFieldArray<T>(path: string): FieldArray<T>
function useFieldArray<T>(form: Form, path: string): FieldArray<T>
返回值说明
fields{ key, index, path, value }[] —— key 用于 v-for,path 用于错误和 touch
append(value)、prepend(value)在末尾 / 开头添加行
insert(index, value)插入行
remove(index)删除行
move(from, to)、swap(a, b)调整行的顺序
replace(values)替换整个列表

不传 form 时从上下文获取表单。如果 values 中没有该数组,会自动创建。直接修改(form.values.items.push(...))同样有效 —— 新行会获得键。

示例 ​

vue
<script setup lang="ts">
const Order = object({
  items: pipe(array(object({ title: pipe(string(), minLength(2)), qty: pipe(coerce.number(), min(1)) })), minLength(1)),
});

const form = useForm(Order, { initial: { items: [{ title: '', qty: '1' }] } });
const items = useFieldArray<{ title: string; qty: string }>(form, 'items');
</script>

<template>
  <div v-for="field in items.fields.value" :key="field.key">
    <input v-model="field.value.title" :name="`${field.path}.title`" @blur="form.touch(`${field.path}.title`)" />
    <span>{{ form.errors[`${field.path}.title`] }}</span>

    <input v-model="field.value.qty" :name="`${field.path}.qty`" @blur="form.touch(`${field.path}.qty`)" />

    <button type="button" :disabled="field.index === 0" @click="items.move(field.index, field.index - 1)">↑</button>
    <button type="button" @click="items.remove(field.index)">×</button>
  </div>
  <button type="button" @click="items.append({ title: '', qty: '1' })">+</button>
</template>

为什么不用索引作为 :key:删除第一行后所有索引都会移动,Vue 会复用错误行的输入框 —— 焦点和已输入的文本会“跳动”。

另请参阅 ​