关键在于将表单项标准化为可比较的原始唯一标识(如${name}|${email}|${phone||''}),用Set管理去重,动态维护prevKey实现增删查,并批量更新isDuplicate状态供模板高亮使用。
直接用 Set 判断对象是否重复行不通,因为对象默认按引用比较。要实现复杂表单中重复项的实时高亮提醒,关键在于把每个表单项“标准化为可比较的原始值”,再交由 Set 管理去重逻辑。
提取稳定、可序列化的唯一标识
对每个表单项(如一行输入框组合),需定义一组能代表其业务唯一性的字段,并将它们组合成字符串或数字等原始类型。不能直接用 JSON.stringify(obj),因为属性顺序、空格、undefined 处理不一致,容易误判。
推荐用确定顺序的键名拼接,例如:
对数值或布尔值,统一转为字符串并处理 null/undefined(如转为空字符串或 'null')
若涉及日期,统一格式化为 ISO 字符串(
)
用 Set 存储已出现的标识,并动态更新
维护一个全局 Set 实例,每次用户修改任意字段时,重新计算当前行的标识值,然后检查该值是否已在 Set 中存在。同时,旧标识要从 Set 中移除,新标识加入——这需要记录上一次的标识。
在表单项组件内保存
状态,初始为 null
计算新 key 后,先
,再
,最后更新
若新 key 已存在(
),则标记该项为重复
配合响应式状态实现高亮渲染
不要在渲染时反复调用 Set.has(),而应在数据变更后,批量计算每行的
标志,存入对应项的状态中。这样模板里只需读取布尔值即可。
例如:表单数据结构为
每次 change 触发后,遍历 items,为每项生成 key,用 Set 判断是否重复,并更新
模板中用
控制样式
注意边界与性能细节
用户快速连输、粘贴、撤销等操作可能导致中间态混乱,需加防抖或依赖框架的更新时机(如 Vue 的 nextTick、React 的 useEffect)确保 Set 和 UI 同步。
避免在 input 事件中高频执行 Set 操作,可节流至 100ms 内最多一次全量校验
删除某一行时,记得从 Set 中清除其对应的 key
初始化表单时,需遍历原始数据,逐个 add 到 Set,而不是直接 new Set(data.map(...)) —— 因为初始就可能含重复
本质不是靠 Set 多神奇,而是把“人眼认为重复”的逻辑,翻译成机器可比对的原始值。Set 只是高效执行“查重”这个动作的工具。
`${item.name}|${item.email}|${item.phone || ''}`item.date?.toISOString().slice(0,10)prevKeyset.delete(prevKey)set.add(newKey)prevKey = newKeyset.has(newKey) && newKey !== prevKeyisDuplicateitems: { name, email, phone, isDuplicate }[]isDuplicateclass="form-row {{ item.isDuplicate ? 'duplicate' : '' }}"