Vee-validate:如何获取所有已修改(dirty)字段
在Vee-Validate的useForm中提取变更字段(支持嵌套结构)
核心思路
由于useForm未提供单独查询每个字段dirty状态的API,我们可以通过对比表单初始值与当前值的方式,递归筛选出所有实际修改过的字段,适配扁平与深层嵌套对象结构。
实现步骤
1. 保存表单初始值
初始化useForm时,深拷贝一份初始值作为对比基准,避免响应式引用导致对比失效:
<script setup> import { useForm } from 'vee-validate'; import { toRaw } from 'vue'; // 定义表单初始值 const initialValues = { name: '', contact: { email: '', phone: '' }, address: { city: '', detail: '' } }; // 初始化表单 const { values, handleSubmit } = useForm({ initialValues, }); // 深拷贝初始值(现代浏览器可用structuredClone,兼容场景可换JSON序列化) const formInitialState = structuredClone(initialValues); // 兼容备选:const formInitialState = JSON.parse(JSON.stringify(initialValues)); </script>
2. 编写递归对比函数
实现递归函数,遍历对象属性并对比初始值与当前值,仅保留变更后的字段:
function getChangedFields(initial, current) { const changed = {}; // 基本类型直接对比 if (initial === current) return null; // 数组处理(按需扩展,示例为基础对比逻辑) if (Array.isArray(initial) && Array.isArray(current)) { const hasDiff = current.some((item, index) => !Object.is(item, initial[index])); return hasDiff ? current : null; } // 对象类型递归对比 if (typeof initial === 'object' && initial !== null && typeof current === 'object' && current !== null) { Object.keys(current).forEach(key => { const fieldDiff = getChangedFields(initial[key], current[key]); if (fieldDiff !== null) { changed[key] = fieldDiff; } }); return Object.keys(changed).length > 0 ? changed : null; } // 基本类型不相等,返回当前值 return current; }
3. 提交时提取变更字段
在表单提交回调中,调用对比函数获取变更字段,仅提交该部分内容:
const onSubmit = handleSubmit((values) => { // 转换为原始对象,避免响应式代理干扰对比 const rawValues = toRaw(values); // 获取变更字段 const changedFields = getChangedFields(formInitialState, rawValues); if (changedFields) { // 仅提交变更内容到后端 console.log('提交变更字段:', changedFields); // api.update(changedFields); } else { console.log('无字段变更,无需提交'); } });
注意事项
- 若表单包含Date、函数、Symbol等特殊类型,需自定义深拷贝逻辑,避免
structuredClone或JSON序列化失效。 - 数组对比逻辑可根据业务需求调整:比如需保留索引变更、或仅对比元素内容,可扩展对应处理分支。
- 必须使用
toRaw转换响应式values为原始对象,确保对比结果准确。
内容的提问来源于stack exchange,提问作者StrikeAgainst
相关产品推荐
相关产品推荐

