UNPKG

tina-weapp

Version:
143 lines (129 loc) 5.12 kB
import { getObjByKey, isNotEmptyObject, noop } from './utils' const ARRAYTYPE = '[object Array]' const OBJECTTYPE = '[object Object]' const FUNCTIONTYPE = '[object Function]' let resultMap = [], ctxMap = [] export default function diffData (ctx, data, cb) { data = JSON.parse(JSON.stringify(data)) const diffResult = diff(data, ctx._rawData) const result = getObjByKey(diffResult) let isNotEmptyObj = !!isNotEmptyObject(result) cb = cb || noop let { _setDataBackup: { setData } } = ctx if (isNotEmptyObj) { setData.call(ctx, result, cb) resultMap.push(result) ctxMap.push(ctx) wx.nextTick(() => { if (resultMap.length) { resultMap.map((obj, index) => { let context = ctxMap[index] Object.keys(obj).forEach(key => { updateRawData(context, key, obj[key]) }) }) resultMap = [], ctxMap = [] } }) } } function updateRawData (ctx, key, value) { const path = key.replace(/\[(\d+?)\]/g, '.$1').split('.') path.reduce((acc, cur, index) => { if (index == path.length - 1) { acc[cur] = value } return acc[cur] }, ctx._rawData) } function diff (current, pre) { const result = {} syncKeys(current, pre) _diff(current, pre, '', result) return result } function syncKeys (current, pre) { if (current === pre) return const rootCurrentType = type(current) const rootPreType = type(pre) if (rootCurrentType == OBJECTTYPE && rootPreType == OBJECTTYPE) { for (let key in pre) { const currentValue = current[key] if (currentValue === undefined) { current[key] = null } else { syncKeys(currentValue, pre[key]) } } } else if (rootCurrentType == ARRAYTYPE && rootPreType == ARRAYTYPE) { if (current.length >= pre.length) { pre.forEach((item, index) => { syncKeys(current[index], item) }) } } } function _diff (current, pre, path, result) { if (current === pre) return const rootCurrentType = type(current) const rootPreType = type(pre) if (rootCurrentType == OBJECTTYPE) { if (rootPreType != OBJECTTYPE || Object.keys(current).length < Object.keys(pre).length && path != '') { setResult(result, path, current) } else { for (let key in current) { const currentValue = current[key] const preValue = pre[key] const currentType = type(currentValue) const preType = type(preValue) if (currentType != ARRAYTYPE && currentType != OBJECTTYPE) { if (currentValue != pre[key]) { setResult(result, (path == '' ? '' : path + ".") + key, currentValue) } } else if (currentType == ARRAYTYPE) { if (preType != ARRAYTYPE) { setResult(result, (path == '' ? '' : path + ".") + key, currentValue) } else { if (currentValue.length < preValue.length) { setResult(result, (path == '' ? '' : path + ".") + key, currentValue) } else { currentValue.forEach((item, index) => { _diff(item, preValue[index], (path == '' ? '' : path + ".") + key + '[' + index + ']', result) }) } } } else if (currentType == OBJECTTYPE) { if (preType != OBJECTTYPE || Object.keys(currentValue).length < Object.keys(preValue).length) { setResult(result, (path == '' ? '' : path + ".") + key, currentValue) } else { for (let subKey in currentValue) { _diff(currentValue[subKey], preValue[subKey], (path == '' ? '' : path + ".") + key + '.' + subKey, result) } } } } } } else if (rootCurrentType == ARRAYTYPE) { if (rootPreType != ARRAYTYPE) { setResult(result, path, current) } else { if (current.length < pre.length) { setResult(result, path, current) } else { current.forEach((item, index) => { _diff(item, pre[index], path + '[' + index + ']', result) }) } } } else { setResult(result, path, current) } } function setResult (result, k, v) { if (type(v) != FUNCTIONTYPE) { result[k] = v } } function type (obj) { return Object.prototype.toString.call(obj) }