2020-05-08 05:01:40
实现表单差异比较并显示修改内容的核心步骤如下:
数据快照(Snapshot)
表单加载时,立即获取所有字段的初始值并存储为独立变量(如通过深拷贝JSON.parse(JSON.stringify(originalObject)))。
确保快照数据不受后续操作影响,作为后续对比的基准。
实时或提交前对比
实时对比:为每个输入框(input、select、textarea等)添加input或change事件监听器,用户修改时立即触发对比逻辑。
提交前对比:在用户点击“提交”按钮时进行一次性对比,减少性能开销,但无法实时显示变化。
推荐:实时高亮用户体验更佳,适合复杂表单;提交前对比适合简单场景。
差异检测逻辑
遍历当前表单数据与快照数据,逐字段比较值是否相等。
注意事项:
数据类型转换:如数字1与字符串'1'需统一类型(如String(currentValue) !== String(originalValue))。
空值处理:区分null、undefined和空字符串''。
复杂结构:对数组或嵌套对象使用深度比较工具(如Lodash的isEqual)。
修改内容显示
高亮显示:为已修改字段添加CSS类(如.changed-field),通过背景色、边框或字体颜色变化突出显示。
列表展示:在表单旁或弹窗中列出修改字段,显示“旧值”和“新值”,便于审核。
Diff工具:对富文本内容集成专用库(如diff-match-patch),细粒度显示文本增删改。
状态管理与回滚(可选)
使用前端框架(如React、Vue)的状态管理机制(如useState、data)维护原始数据和当前数据。
提供“撤销”功能,将字段值还原至快照中的原始值。
前端实现实时差异检测与高亮的代码示例
初始数据快照
const myForm = document.getElementById('myForm');let originalFormData = {};function captureOriginalData() { const formElements = myForm.elements; for (let i = 0; i < formElements.length; i++) { const element = formElements[i]; if (element.name && (element.type !== 'submit' && element.type !== 'button')) { originalFormData[element.name] = element.type === 'checkbox' || element.type === 'radio' ? element.checked : element.value; } }}document.addEventListener('DOMContentLoaded', captureOriginalData);事件监听与实时比较
myForm.addEventListener('input', (event) => { const target = event.target; if (target.name && (target.type !== 'submit' && target.type !== 'button')) { const currentValue = target.type === 'checkbox' || target.type === 'radio' ? target.checked : target.value; const originalValue = originalFormData[target.name]; if (String(currentValue) !== String(originalValue)) { target.classList.add('changed-field'); } else { target.classList.remove('changed-field'); } }});CSS样式定义
.changed-field { background-color: #fffacd; border: 1px solid #f0ad4e; transition: background-color 0.3s ease, border-color 0.3s ease;}.changed-field::placeholder { color: #d9534f;}后端处理差异数据与记录变更日志的步骤
接收完整数据
后端API(如PUT/PATCH请求)接收前端提交的完整表单数据,代表用户编辑后的最新状态。
获取原始数据
根据唯一标识(如用户ID、订单ID)从数据库查询原始记录,作为对比基准。
后端差异比对
遍历新数据字段,检查是否在原始数据中存在:
若存在且值不等,或字段在新数据中新增,则标记为“已变更”。
使用ORM框架(如Sequelize)或手动编写逻辑实现字段级更新。
更新数据库与记录日志
更新数据库:仅修改有变化的字段(部分ORM支持自动处理)。
记录审计日志:将变更信息存入日志表,包含以下字段:
log_id(唯一ID)、entity_type(实体类型)、entity_id(实体ID)、field_name(字段名)、old_value(旧值)、new_value(新值)、changed_by_user_id(操作用户ID)、changed_at(时间戳)、ip_address(IP地址)、action_type(操作类型)。
实现方式
业务逻辑层:在服务层手动编写日志记录代码,灵活可控。
数据库触发器:通过触发器自动记录变更,但逻辑复杂且调试困难。
ORM/框架功能:利用内置审计功能(如Django的django-reversion)简化流程。
差异比较与高亮显示的意义