moy-dom
Version:
A flexiable Virtual DOM library for building modern web interface.
113 lines (100 loc) • 3.06 kB
JavaScript
import makeKeyIndexAndFree from './makeKeyIndexAndFree'
import remove from './remove'
import move from './move'
import insert from './insert'
import append from './append'
/**
* [listDiff diff two List]
* @param {[Array]} newList [the new List]
* @param {[Array]} oldList [the old List]
* @return {[Object]} [a children property for deep compare and a changes for two list's diffs]
*
* @changes's type
* 0 -> remove
* 1 -> move
* 2 -> insert
* 3 -> append
*/
export default function listDiff(newList, oldList){
const {
keyIndex: newKeyIndex,
free: newFree,
} = makeKeyIndexAndFree(newList), // need keyIndex Map for eazy to find key
children = [], // the same struct as old list for deep compare
changes = [], // the changes
newFreeLength = newFree.length
let newFreeIndex = 0,
hittingItemKeyIndex,
oldItemKey
// first we get old list same struct children for deep compare
for(let oldItem of oldList){
oldItemKey = oldItem.key
if(oldItemKey !== undefined){
hittingItemKeyIndex = newKeyIndex.get(oldItemKey)
children.push(
hittingItemKeyIndex !== undefined ? newList[hittingItemKeyIndex] : null
)
}else{
// original place
children.push(
newFreeIndex < newFreeLength ? newFree[newFreeIndex ++] : null
)
}
}
const simulateList = [...children] // the simulate for list changes
let simulateIndex = 0, simulateLength = simulateList.length
// remove null items represent not exit items in new list
while(simulateIndex < simulateLength){
if(simulateList[simulateIndex] === null){
remove(simulateIndex, simulateList, changes)
simulateLength --
}else{
simulateIndex ++
}
}
simulateIndex = 0
let newIndex = 0,
newLength = newList.length,
simulateKeyIndex, // may need simulateKeyIndex for deep compare
simulateItem,
simulateItemKey,
newItem,
newItemKey
// point to point compare
while(simulateIndex < simulateLength &&
newIndex < newLength){
simulateItem = simulateList[simulateIndex]
simulateItemKey = simulateItem.key
newItem = newList[newIndex]
newItemKey = newItem.key
// the same node
if(newItemKey === simulateItemKey){
simulateIndex ++
newIndex ++
}else{
if(!simulateKeyIndex){
// get simulateKeyIndex
simulateKeyIndex = makeKeyIndexAndFree(simulateList).keyIndex
}
if((hittingItemKeyIndex = simulateKeyIndex.get(newItemKey))){
// find the same key in old list, just move it
move(newIndex ++, hittingItemKeyIndex, simulateList, changes)
simulateIndex ++
}else{
// otherwise inset a new one
insert(newIndex, newItem, simulateList, changes)
simulateLength ++
simulateIndex ++
newIndex ++
}
}
}
// rest new list item should be append
while(newIndex < newLength){
append(newList[newIndex ++], simulateList, changes)
}
return {
children,
changes,
}
}