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 переиспользует поля не тех строк — фокус и введённый текст «перепрыгивают».