后台传过来一个对象数组,vue渲染到页面中,然后修改了这个对象数组,可能是增删改了其中的某些对象。但是不是操作一下就发到后台去保存,而是只是前端页面在发生变化,最后点击提交按钮的时候才把变化过的数据传到后台去更新。
而且后台更新的时候,不是把这整个数组替换成新的,而是改动里面的一部分。
所以最后一步发送到后台的时候,前端就需要比较新的对象数组相比于原来的对象数组做了什么操作。然后把这些操作发送到后台。
以下是比较的算法,刚开始我是把list1和list2都遍历了一遍,觉得效率低就改为了下面的。

/**
 * 判断对象是否为空
 * @param obj 对象
 * @returns {boolean} 为空返回true,不为空返回false
 */
function isEmptyObj(obj) {
    //如果对象的键数组的长度是0,表示为空对象
    return Object.keys(obj).length === 0;
}

/**
 * 找到两个相同结构的对象的差异内容,并返回包含所有差异的数组
 * 注意对象内的值只能是简单类型,复杂类型不考虑
 * @param obj1 原对象
 * @param obj2 可能修改过的对象
 * @returns {{}} 包含所有差异的数组
 */
function findObjOperate(obj1, obj2) {
    const resultObj = {};
    //遍历obj1的键数组,因为obj1和obj2结构相同,所以不考虑结构上的差异
    Object.keys(obj1).forEach(key => {
        if (obj1[key] !== obj2[key]) {
            //将变化过的属性挂载到返回对象中
            resultObj[key] = obj2[key];
        }
    });
    return resultObj;
}

/**
 * 找到两个对象数组的差异,并打印从list1到list2的所有变化
 * 注意约定id不能修改
 * @param list1 原数组
 * @param list2 可能修改过的数组
 */
function findOperate(list1, list2) {
    //用于记录id值和索引值之间差别的平衡值(以下简称平衡值)
    let step = 0;
    //遍历list2
    list2.forEach((obj2, index) => {
        //当前id和平衡过差值后的索引值(以下简称新索引值)还是不等
        if (obj2.id !== index + step) {
            //当前id和新索引值之间的差值就是被删除对象的个数
            for (let j = index + step; j < obj2.id; j++) {
                console.log('delete', list1[j]);
            }
            //更新平衡值
            step = obj2.id - index;
        }
        //根据新索引值在list1中找到对应的对象
        const obj1 = list1[index + step];
        if (obj1) {
            //比较obj1和obj2的差异
            const objOperateObj = findObjOperate(obj1, obj2);
            //如果返回的对象为空对象,表示没有差异
            if (!isEmptyObj(objOperateObj)) {
                console.log('modify', obj1.id,objOperateObj);
            }
        } else {
            //js没有下标越界,所以如果obj1是undefined,那么obj2就是新增出的对象
            console.log('add', obj2);
        }
    });
}

用两个对象数组去测试,假设页面数据从user1变成了user2。

const user1 = [{id: 0, name: 'zhangsan', age: 18}, {id: 1, name: 'lisi', age: 19}, {id: 2, name: 'wangwu', age: 20}, {id: 3, name: 'wangwu', age: 20}];
const user2 = [{id: 0, name: 'zhangsan2', age: 19}, {id: 3, name: 'wangwu', age: 20}, {id: 4, name: 'xinren', age: 100}];

findOperate(user1, user2);

打印结果为

modify 0 { name: 'zhangsan2', age: 19 }
delete { id: 1, name: 'lisi', age: 19 }
delete { id: 2, name: 'wangwu', age: 20 }
add { id: 4, name: 'xinren', age: 100 }

从user1到user2,原id为0的对象,name改为了zhangsan2,age改为了19。
原id为1和2的对象被删除。
新增了id为4的对象。

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐