|
| 1 | +import Vue from 'core/index' |
| 2 | +import { diffLog } from './runtime-trace' |
| 3 | + |
| 4 | +function getDeepData (keyList, viewData) { |
| 5 | + if (keyList.length > 1) { |
| 6 | + const _key = keyList.splice(0, 1) |
| 7 | + const _viewData = viewData[_key] |
| 8 | + if (_viewData) { |
| 9 | + return getDeepData(keyList, _viewData) |
| 10 | + } else { |
| 11 | + return null |
| 12 | + } |
| 13 | + } else { |
| 14 | + if (viewData[keyList[0]]) { |
| 15 | + return viewData[keyList[0]] |
| 16 | + } else { |
| 17 | + return null |
| 18 | + } |
| 19 | + } |
| 20 | +} |
| 21 | +function compareAndSetDeepData (key, newData, vm, data) { |
| 22 | + // 比较引用类型数据 |
| 23 | + try { |
| 24 | + const keyList = key.split('.') |
| 25 | + const oldData = getDeepData(keyList, vm.$root.$mp.page.__viewData__) |
| 26 | + if (oldData === null || JSON.stringify(oldData) !== JSON.stringify(newData)) { |
| 27 | + data[key] = newData |
| 28 | + } |
| 29 | + } catch (e) { |
| 30 | + console.log(e, key, newData, vm) |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +function cleanKeyPath (vm) { |
| 35 | + if (vm.__mpKeyPath) { |
| 36 | + Object.keys(vm.__mpKeyPath).forEach((_key) => { |
| 37 | + delete vm.__mpKeyPath[_key]['__keyPath'] |
| 38 | + }) |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +function minifyDeepData (rootKey, originKey, vmData, data, _mpValueSet, vm) { |
| 43 | + try { |
| 44 | + if (vmData instanceof Array) { |
| 45 | + // 数组 |
| 46 | + compareAndSetDeepData(rootKey + '.' + originKey, vmData, vm, data) |
| 47 | + } else { |
| 48 | + // Object |
| 49 | + let __keyPathOnThis = {} // 存储这层对象的keyPath |
| 50 | + if (vmData.__keyPath) { |
| 51 | + // 有更新列表 ,按照更新列表更新 |
| 52 | + __keyPathOnThis = vmData.__keyPath |
| 53 | + Object.keys(vmData).forEach((_key) => { |
| 54 | + if (vmData[_key] instanceof Object) { |
| 55 | + // 引用类型 递归 |
| 56 | + if (_key === '__keyPath') { |
| 57 | + return |
| 58 | + } |
| 59 | + minifyDeepData(rootKey + '.' + originKey, _key, vmData[_key], data, null, vm) |
| 60 | + } else { |
| 61 | + // 更新列表中的 加入data |
| 62 | + if (__keyPathOnThis[_key] === true) { |
| 63 | + if (originKey) { |
| 64 | + data[rootKey + '.' + originKey + '.' + _key] = vmData[_key] |
| 65 | + } else { |
| 66 | + data[rootKey + '.' + _key] = vmData[_key] |
| 67 | + } |
| 68 | + } |
| 69 | + } |
| 70 | + }) |
| 71 | + // 根节点可能有父子引用同一个引用类型数据,依赖树都遍历完后清理 |
| 72 | + vm['__mpKeyPath'] = vm['__mpKeyPath'] || {} |
| 73 | + vm['__mpKeyPath'][vmData.__ob__.dep.id] = vmData |
| 74 | + } else { |
| 75 | + // 没有更新列表 |
| 76 | + compareAndSetDeepData(rootKey + '.' + originKey, vmData, vm, data) |
| 77 | + } |
| 78 | + } |
| 79 | + } catch (e) { |
| 80 | + console.log(e, rootKey, originKey, vmData, data) |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +function getRootKey (vm, rootKey) { |
| 85 | + if (!vm.$parent.$attrs) { |
| 86 | + rootKey = '$root.0' + ',' + rootKey |
| 87 | + return rootKey |
| 88 | + } else { |
| 89 | + rootKey = vm.$parent.$attrs.mpcomid + ',' + rootKey |
| 90 | + return getRootKey(vm.$parent, rootKey) |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +export function diffData (vm, data) { |
| 95 | + const vmData = vm._data || {} |
| 96 | + const vmProps = vm._props || {} |
| 97 | + let rootKey = '' |
| 98 | + if (!vm.$attrs) { |
| 99 | + rootKey = '$root.0' |
| 100 | + } else { |
| 101 | + rootKey = getRootKey(vm, vm.$attrs.mpcomid) |
| 102 | + } |
| 103 | + Vue.nextTick(() => { |
| 104 | + cleanKeyPath(vm) |
| 105 | + }) |
| 106 | + // console.log(rootKey) |
| 107 | + |
| 108 | + // 值类型变量不考虑优化,还是直接更新 |
| 109 | + const __keyPathOnThis = vmData.__keyPath || vm.__keyPath || {} |
| 110 | + delete vm.__keyPath |
| 111 | + delete vmData.__keyPath |
| 112 | + delete vmProps.__keyPath |
| 113 | + if (vm._mpValueSet === 'done') { |
| 114 | + // 第二次赋值才进行缩减操作 |
| 115 | + Object.keys(vmData).forEach((vmDataItemKey) => { |
| 116 | + if (vmData[vmDataItemKey] instanceof Object) { |
| 117 | + // 引用类型 |
| 118 | + if (vmDataItemKey === '__keyPath') { return } |
| 119 | + minifyDeepData(rootKey, vmDataItemKey, vmData[vmDataItemKey], data, vm._mpValueSet, vm) |
| 120 | + } else { |
| 121 | + // _data上的值属性只有要更新的时候才赋值 |
| 122 | + if (__keyPathOnThis[vmDataItemKey] === true) { |
| 123 | + data[rootKey + '.' + vmDataItemKey] = vmData[vmDataItemKey] |
| 124 | + } |
| 125 | + } |
| 126 | + }) |
| 127 | + |
| 128 | + Object.keys(vmProps).forEach((vmPropsItemKey) => { |
| 129 | + if (vmProps[vmPropsItemKey] instanceof Object) { |
| 130 | + // 引用类型 |
| 131 | + if (vmPropsItemKey === '__keyPath') { return } |
| 132 | + minifyDeepData(rootKey, vmPropsItemKey, vmProps[vmPropsItemKey], data, vm._mpValueSet, vm) |
| 133 | + } else { |
| 134 | + data[rootKey + '.' + vmPropsItemKey] = vmProps[vmPropsItemKey] |
| 135 | + } |
| 136 | + // _props上的值属性只有要更新的时候才赋值 |
| 137 | + }) |
| 138 | + |
| 139 | + // 检查完data和props,最后补上_mpProps & _computedWatchers |
| 140 | + const vmMpProps = vm._mpProps || {} |
| 141 | + const vmComputedWatchers = vm._computedWatchers || {} |
| 142 | + Object.keys(vmMpProps).forEach((mpItemKey) => { |
| 143 | + data[rootKey + '.' + mpItemKey] = vmMpProps[mpItemKey] |
| 144 | + }) |
| 145 | + Object.keys(vmComputedWatchers).forEach((computedItemKey) => { |
| 146 | + data[rootKey + '.' + computedItemKey] = vmComputedWatchers[computedItemKey] |
| 147 | + }) |
| 148 | + // 更新的时候要删除$root.0:{},否则会覆盖原正确数据 |
| 149 | + delete data[rootKey] |
| 150 | + } |
| 151 | + if (vm._mpValueSet === undefined) { |
| 152 | + // 第一次设置数据成功后,标记位置true,再更新到这个节点如果没有keyPath数组认为不需要更新 |
| 153 | + vm._mpValueSet = 'done' |
| 154 | + } |
| 155 | + if (Vue.config.devtools) { |
| 156 | + // console.log('更新VM节点', vm) |
| 157 | + // console.log('实际传到Page.setData数据', data) |
| 158 | + diffLog(data) |
| 159 | + } |
| 160 | +} |
0 commit comments